|
17 | 17 | import jakarta.inject.Inject; |
18 | 18 | import jakarta.inject.Singleton; |
19 | 19 |
|
20 | | -import com.google.gson.JsonParser; |
21 | 20 | import com.google.gson.JsonSyntaxException; |
22 | 21 | import io.quarkus.security.Authenticated; |
23 | 22 | import io.quarkus.security.ForbiddenException; |
|
30 | 29 | import org.a2aproject.sdk.compat03.conversion.A2AProtocol_v0_3; |
31 | 30 | import org.a2aproject.sdk.compat03.json.JsonProcessingException_v0_3; |
32 | 31 | import org.a2aproject.sdk.compat03.json.JsonUtil_v0_3; |
33 | | -import org.a2aproject.sdk.compat03.spec.AgentCard_v0_3; |
34 | 32 | import org.a2aproject.sdk.compat03.spec.CancelTaskRequest_v0_3; |
35 | 33 | import org.a2aproject.sdk.compat03.spec.DeleteTaskPushNotificationConfigRequest_v0_3; |
36 | 34 | import org.a2aproject.sdk.compat03.spec.GetAuthenticatedExtendedCardRequest_v0_3; |
37 | 35 | import org.a2aproject.sdk.compat03.spec.GetTaskPushNotificationConfigRequest_v0_3; |
38 | 36 | import org.a2aproject.sdk.compat03.spec.GetTaskRequest_v0_3; |
39 | 37 | import org.a2aproject.sdk.compat03.spec.InternalError_v0_3; |
40 | | -import org.a2aproject.sdk.compat03.spec.InvalidParamsError_v0_3; |
41 | | -import org.a2aproject.sdk.compat03.spec.InvalidRequestError_v0_3; |
42 | 38 | import org.a2aproject.sdk.compat03.spec.JSONParseError_v0_3; |
43 | 39 | import org.a2aproject.sdk.compat03.spec.JSONRPCError_v0_3; |
44 | 40 | import org.a2aproject.sdk.compat03.spec.JSONRPCErrorResponse_v0_3; |
45 | | -import org.a2aproject.sdk.compat03.spec.JSONRPCMessage_v0_3; |
46 | 41 | import org.a2aproject.sdk.compat03.spec.JSONRPCRequest_v0_3; |
47 | 42 | import org.a2aproject.sdk.compat03.spec.JSONRPCResponse_v0_3; |
48 | 43 | import org.a2aproject.sdk.compat03.spec.ListTaskPushNotificationConfigRequest_v0_3; |
49 | | -import org.a2aproject.sdk.compat03.spec.MethodNotFoundError_v0_3; |
50 | 44 | import org.a2aproject.sdk.compat03.spec.NonStreamingJSONRPCRequest_v0_3; |
51 | 45 | import org.a2aproject.sdk.compat03.spec.SendMessageRequest_v0_3; |
52 | 46 | import org.a2aproject.sdk.compat03.spec.SendStreamingMessageRequest_v0_3; |
|
55 | 49 | import org.a2aproject.sdk.compat03.spec.TaskResubscriptionRequest_v0_3; |
56 | 50 | import org.a2aproject.sdk.compat03.spec.UnsupportedOperationError_v0_3; |
57 | 51 | import org.a2aproject.sdk.compat03.transport.jsonrpc.handler.JSONRPCHandler_v0_3; |
| 52 | +import org.a2aproject.sdk.compat03.transport.jsonrpc.handler.JSONRPCRequestDecoder_v0_3; |
58 | 53 | import org.a2aproject.sdk.compat03.util.Utils_v0_3; |
59 | 54 | import org.a2aproject.sdk.server.PublicAgentCard; |
60 | 55 | import org.a2aproject.sdk.server.ServerCallContext; |
@@ -131,56 +126,31 @@ private static boolean hasNonDefaultV10AgentCard() { |
131 | 126 | } |
132 | 127 |
|
133 | 128 | @Authenticated |
134 | | - public void invokeJSONRPCHandler(String body, RoutingContext rc) { |
| 129 | + public void invokeJSONRPCHandler(@Nullable String body, RoutingContext rc) { |
135 | 130 | boolean streaming = false; |
136 | 131 | ServerCallContext context = createCallContext(rc); |
137 | 132 | JSONRPCResponse_v0_3<?> nonStreamingResponse = null; |
138 | 133 | Multi<? extends JSONRPCResponse_v0_3<?>> streamingResponse = null; |
139 | 134 | JSONRPCErrorResponse_v0_3 error = null; |
140 | 135 | Object requestId = null; |
141 | 136 | try { |
142 | | - com.google.gson.JsonObject node; |
143 | | - try { |
144 | | - node = JsonParser.parseString(body).getAsJsonObject(); |
145 | | - } catch (Exception e) { |
146 | | - throw new JSONParseError_v0_3(e.getMessage()); |
147 | | - } |
148 | | - |
149 | | - // Extract id field early so error responses can include it |
150 | | - com.google.gson.JsonElement idElement = node.get("id"); |
151 | | - if (idElement != null && !idElement.isJsonNull() && !idElement.isJsonPrimitive()) { |
152 | | - throw new InvalidRequestError_v0_3("Invalid JSON-RPC request: 'id' must be a string, number, or null"); |
153 | | - } |
154 | | - if (idElement != null && !idElement.isJsonNull() && idElement.isJsonPrimitive()) { |
155 | | - com.google.gson.JsonPrimitive idPrimitive = idElement.getAsJsonPrimitive(); |
156 | | - requestId = idPrimitive.isNumber() ? idPrimitive.getAsLong() : idPrimitive.getAsString(); |
157 | | - } |
158 | | - |
159 | | - // Validate jsonrpc field |
160 | | - com.google.gson.JsonElement jsonrpcElement = node.get("jsonrpc"); |
161 | | - if (jsonrpcElement == null || !jsonrpcElement.isJsonPrimitive() |
162 | | - || !JSONRPCMessage_v0_3.JSONRPC_VERSION.equals(jsonrpcElement.getAsString())) { |
163 | | - throw new InvalidRequestError_v0_3("Invalid JSON-RPC request: missing or invalid 'jsonrpc' field"); |
164 | | - } |
165 | | - |
166 | | - // Validate method field |
167 | | - com.google.gson.JsonElement methodElement = node.get("method"); |
168 | | - if (methodElement == null || !methodElement.isJsonPrimitive()) { |
169 | | - throw new InvalidRequestError_v0_3("Invalid JSON-RPC request: missing or invalid 'method' field"); |
| 137 | + JSONRPCRequestDecoder_v0_3.DecodeResult result = JSONRPCRequestDecoder_v0_3.decode(body); |
| 138 | + if (result instanceof JSONRPCRequestDecoder_v0_3.DecodeFailure failure) { |
| 139 | + requestId = failure.requestId(); |
| 140 | + if (failure.methodName() != null) { |
| 141 | + context.getState().put(METHOD_NAME_KEY, failure.methodName()); |
| 142 | + } |
| 143 | + throw failure.error(); |
170 | 144 | } |
171 | | - |
172 | | - String methodName = methodElement.getAsString(); |
173 | | - context.getState().put(METHOD_NAME_KEY, methodName); |
174 | | - |
175 | | - streaming = SendStreamingMessageRequest_v0_3.METHOD.equals(methodName) |
176 | | - || TaskResubscriptionRequest_v0_3.METHOD.equals(methodName); |
177 | | - |
178 | | - if (streaming) { |
179 | | - StreamingJSONRPCRequest_v0_3<?> request = deserializeStreamingRequest(body, methodName); |
| 145 | + JSONRPCRequestDecoder_v0_3.DecodedRequest decoded = (JSONRPCRequestDecoder_v0_3.DecodedRequest) result; |
| 146 | + requestId = decoded.requestId(); |
| 147 | + context.getState().put(METHOD_NAME_KEY, decoded.methodName()); |
| 148 | + if (decoded.request() instanceof StreamingJSONRPCRequest_v0_3<?> request) { |
| 149 | + streaming = true; |
180 | 150 | streamingResponse = processStreamingRequest(request, context); |
181 | 151 | } else { |
182 | | - NonStreamingJSONRPCRequest_v0_3<?> request = deserializeNonStreamingRequest(body, methodName); |
183 | | - nonStreamingResponse = processNonStreamingRequest(request, context); |
| 152 | + nonStreamingResponse = processNonStreamingRequest( |
| 153 | + (NonStreamingJSONRPCRequest_v0_3<?>) decoded.request(), context); |
184 | 154 | } |
185 | 155 | } catch (JSONRPCError_v0_3 e) { |
186 | 156 | error = new JSONRPCErrorResponse_v0_3(requestId, e); |
@@ -212,40 +182,6 @@ private static String formatSseEvent(Object data, long id) { |
212 | 182 | return "data: " + Utils_v0_3.toJsonString(data) + "\nid: " + id + "\n\n"; |
213 | 183 | } |
214 | 184 |
|
215 | | - private NonStreamingJSONRPCRequest_v0_3<?> deserializeNonStreamingRequest(String body, String methodName) { |
216 | | - try { |
217 | | - return switch (methodName) { |
218 | | - case GetTaskRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, GetTaskRequest_v0_3.class); |
219 | | - case CancelTaskRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, CancelTaskRequest_v0_3.class); |
220 | | - case SendMessageRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, SendMessageRequest_v0_3.class); |
221 | | - case SetTaskPushNotificationConfigRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, SetTaskPushNotificationConfigRequest_v0_3.class); |
222 | | - case GetTaskPushNotificationConfigRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, GetTaskPushNotificationConfigRequest_v0_3.class); |
223 | | - case ListTaskPushNotificationConfigRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, ListTaskPushNotificationConfigRequest_v0_3.class); |
224 | | - case DeleteTaskPushNotificationConfigRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, DeleteTaskPushNotificationConfigRequest_v0_3.class); |
225 | | - case GetAuthenticatedExtendedCardRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, GetAuthenticatedExtendedCardRequest_v0_3.class); |
226 | | - default -> throw new MethodNotFoundError_v0_3(); |
227 | | - }; |
228 | | - } catch (JSONRPCError_v0_3 e) { |
229 | | - throw e; |
230 | | - } catch (Exception e) { |
231 | | - throw new InvalidParamsError_v0_3(e.getMessage()); |
232 | | - } |
233 | | - } |
234 | | - |
235 | | - private StreamingJSONRPCRequest_v0_3<?> deserializeStreamingRequest(String body, String methodName) { |
236 | | - try { |
237 | | - return switch (methodName) { |
238 | | - case SendStreamingMessageRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, SendStreamingMessageRequest_v0_3.class); |
239 | | - case TaskResubscriptionRequest_v0_3.METHOD -> JsonUtil_v0_3.fromJson(body, TaskResubscriptionRequest_v0_3.class); |
240 | | - default -> throw new MethodNotFoundError_v0_3(); |
241 | | - }; |
242 | | - } catch (JSONRPCError_v0_3 e) { |
243 | | - throw e; |
244 | | - } catch (Exception e) { |
245 | | - throw new InvalidParamsError_v0_3(e.getMessage()); |
246 | | - } |
247 | | - } |
248 | | - |
249 | 185 | private JSONRPCResponse_v0_3<?> processNonStreamingRequest( |
250 | 186 | NonStreamingJSONRPCRequest_v0_3<?> request, ServerCallContext context) { |
251 | 187 | if (request instanceof GetTaskRequest_v0_3 req) { |
|
0 commit comments