Fix duplicate field declarations in EnhancedMcpServlet
Showing
1 changed file
with
40 additions
and
29 deletions
| ... | @@ -46,17 +46,23 @@ class EnhancedMcpServlet extends HttpServlet { | ... | @@ -46,17 +46,23 @@ class EnhancedMcpServlet extends HttpServlet { |
| 46 | 46 | ||
| 47 | private JsonSlurper jsonSlurper = new JsonSlurper() | 47 | private JsonSlurper jsonSlurper = new JsonSlurper() |
| 48 | 48 | ||
| 49 | // Session state constants | 49 | // Session state constants |
| 50 | private static final int STATE_UNINITIALIZED = 0 | 50 | private static final int STATE_UNINITIALIZED = 0 |
| 51 | private static final int STATE_INITIALIZING = 1 | 51 | private static final int STATE_INITIALIZING = 1 |
| 52 | private static final int STATE_INITIALIZED = 2 | 52 | private static final int STATE_INITIALIZED = 2 |
| 53 | 53 | ||
| 54 | // Simple registry for active connections only (transient HTTP connections) | 54 | // Simple registry for active connections only (transient HTTP connections) |
| 55 | private final Map<String, PrintWriter> activeConnections = new ConcurrentHashMap<>() | 55 | private final Map<String, PrintWriter> activeConnections = new ConcurrentHashMap<>() |
| 56 | 56 | ||
| 57 | // Session management using Moqui's Visit system directly | 57 | // Session management using Moqui's Visit system directly |
| 58 | // No need for separate session manager - Visit entity handles persistence | 58 | // No need for separate session manager - Visit entity handles persistence |
| 59 | private final Map<String, Integer> sessionStates = new ConcurrentHashMap<>() | 59 | private final Map<String, Integer> sessionStates = new ConcurrentHashMap<>() |
| 60 | |||
| 61 | // Message storage for notifications/subscribe and notifications/unsubscribe | ||
| 62 | private final Map<String, List<Map>> sessionMessages = new ConcurrentHashMap<>() | ||
| 63 | |||
| 64 | // In-memory session tracking to avoid database access for read operations | ||
| 65 | private final Map<String, String> sessionUsers = new ConcurrentHashMap<>() | ||
| 60 | 66 | ||
| 61 | // Progress tracking for notifications/progress | 67 | // Progress tracking for notifications/progress |
| 62 | private final Map<String, Map> sessionProgress = new ConcurrentHashMap<>() | 68 | private final Map<String, Map> sessionProgress = new ConcurrentHashMap<>() |
| ... | @@ -64,15 +70,6 @@ class EnhancedMcpServlet extends HttpServlet { | ... | @@ -64,15 +70,6 @@ class EnhancedMcpServlet extends HttpServlet { |
| 64 | // Visit cache to reduce database access and prevent lock contention | 70 | // Visit cache to reduce database access and prevent lock contention |
| 65 | private final Map<String, EntityValue> visitCache = new ConcurrentHashMap<>() | 71 | private final Map<String, EntityValue> visitCache = new ConcurrentHashMap<>() |
| 66 | 72 | ||
| 67 | // In-memory session tracking to avoid database access for read operations | ||
| 68 | private final Map<String, String> sessionUsers = new ConcurrentHashMap<>() | ||
| 69 | |||
| 70 | // Message storage for notifications/message | ||
| 71 | private final Map<String, List<Map>> sessionMessages = new ConcurrentHashMap<>() | ||
| 72 | |||
| 73 | // Subscription tracking for notifications/subscribe and notifications/unsubscribe | ||
| 74 | private final Map<String, Set<String>> sessionSubscriptions = new ConcurrentHashMap<>() | ||
| 75 | |||
| 76 | // Notification queue for server-initiated notifications (for non-SSE clients) | 73 | // Notification queue for server-initiated notifications (for non-SSE clients) |
| 77 | private static final Map<String, List<Map>> notificationQueues = new ConcurrentHashMap<>() | 74 | private static final Map<String, List<Map>> notificationQueues = new ConcurrentHashMap<>() |
| 78 | 75 | ||
| ... | @@ -511,18 +508,32 @@ class EnhancedMcpServlet extends HttpServlet { | ... | @@ -511,18 +508,32 @@ class EnhancedMcpServlet extends HttpServlet { |
| 511 | private void handleJsonRpc(HttpServletRequest request, HttpServletResponse response, ExecutionContextImpl ec, String webappName, String requestBody, def visit) | 508 | private void handleJsonRpc(HttpServletRequest request, HttpServletResponse response, ExecutionContextImpl ec, String webappName, String requestBody, def visit) |
| 512 | throws IOException { | 509 | throws IOException { |
| 513 | 510 | ||
| 514 | // Initialize web facade for proper session management (like SSE connections) | 511 | // Initialize web facade for proper session management |
| 515 | // This prevents the null user loop by ensuring HTTP session is properly linked | ||
| 516 | try { | 512 | try { |
| 517 | // If we have a visit, make sure it's in the request/session before initWebFacade | 513 | // If we have a visit, use it directly (don't create new one) |
| 514 | visit = ec.user.getVisit() | ||
| 518 | if (visit) { | 515 | if (visit) { |
| 519 | request.setAttribute("moqui.visitId", visit.visitId) | ||
| 520 | request.getSession().setAttribute("moqui.visitId", visit.visitId) | 516 | request.getSession().setAttribute("moqui.visitId", visit.visitId) |
| 517 | logger.debug("JSON-RPC web facade initialized for user: ${ec.user?.username} with visit: ${visit.visitId}") | ||
| 518 | } else { | ||
| 519 | // No visit exists, need to create one | ||
| 520 | logger.info("Creating new Visit record for user: ${ec.user?.username}") | ||
| 521 | visit = ec.entity.makeValue("moqui.server.Visit") | ||
| 522 | visit.visitId = ec.userFacade.getVisitId(visit) | ||
| 523 | visit.userId = ec.user.userId | ||
| 524 | visit.sessionId = visit.sessionId | ||
| 525 | visit.userAccountId = ec.user.userAccount?.userAccountId | ||
| 526 | visit.sessionCreatedDate = ec.user.nowTimestamp | ||
| 527 | visit.visitStatus = null | ||
| 528 | visit.lastActiveDate = ec.user.nowTimestamp | ||
| 529 | visit.visitDeletedDate = null | ||
| 530 | ec.entity.create(visit) | ||
| 531 | logger.info("Visit ${visit.visitId} created for user: ${ec.user?.username}") | ||
| 521 | } | 532 | } |
| 522 | ec.initWebFacade(webappName, request, response) | 533 | ec.initWebFacade(webappName, request, response) |
| 523 | logger.debug("JSON-RPC web facade initialized for user: ${ec.user?.username} with visit: ${ec.user.visitId}") | 534 | logger.debug("JSON-RPC web facade initialized for user: ${ec.user?.username} with visit: ${visit.visitId}") |
| 524 | } catch (Exception e) { | 535 | } catch (Exception e) { |
| 525 | logger.warn("JSON-RPC web facade initialization failed: ${e.message}") | 536 | logger.warn("Web facade initialization warning: ${e.message}") |
| 526 | // Continue anyway - we may still have basic user context from auth | 537 | // Continue anyway - we may still have basic user context from auth |
| 527 | } | 538 | } |
| 528 | 539 | ||
| ... | @@ -532,13 +543,13 @@ class EnhancedMcpServlet extends HttpServlet { | ... | @@ -532,13 +543,13 @@ class EnhancedMcpServlet extends HttpServlet { |
| 532 | logger.info("Enhanced MCP JSON-RPC Request: ${method} ${request.requestURI} - Accept: ${acceptHeader}") | 543 | logger.info("Enhanced MCP JSON-RPC Request: ${method} ${request.requestURI} - Accept: ${acceptHeader}") |
| 533 | 544 | ||
| 534 | // Validate Accept header per MCP 2025-11-25 spec requirement #2 | 545 | // Validate Accept header per MCP 2025-11-25 spec requirement #2 |
| 535 | // Client MUST include Accept header with either application/json or text/event-stream | 546 | // Client MUST include Accept header with at least one of: application/json or text/event-stream |
| 536 | if (!acceptHeader || !(acceptHeader.contains("application/json") || acceptHeader.contains("text/event-stream"))) { | 547 | if (!acceptHeader || !acceptHeader.contains("application/json") && !acceptHeader.contains("text/event-stream")) { |
| 537 | response.setStatus(HttpServletResponse.SC_BAD_REQUEST) | 548 | response.setStatus(HttpServletResponse.SC_BAD_REQUEST) |
| 538 | response.setContentType("application/json") | 549 | response.setContentType("application/json") |
| 539 | response.writer.write(JsonOutput.toJson([ | 550 | response.writer.write(JsonOutput.toJson([ |
| 540 | jsonrpc: "2.0", | 551 | jsonrpc: "2.0", |
| 541 | error: [code: -32600, message: "Accept header must include application/json and text/event-stream"], | 552 | error: [code: -32600, message: "Accept header must include application/json or text/event-stream"], |
| 542 | id: null | 553 | id: null |
| 543 | ])) | 554 | ])) |
| 544 | return | 555 | return | ... | ... |
-
Please register or sign in to post a comment