33import static io .vertx .core .http .HttpHeaders .CONTENT_TYPE ;
44import static jakarta .ws .rs .core .MediaType .APPLICATION_JSON ;
55
6+ import java .util .HashMap ;
7+ import java .util .Map ;
8+ import java .util .Set ;
69import java .util .concurrent .Executor ;
710import java .util .concurrent .Flow ;
811import java .util .concurrent .atomic .AtomicLong ;
1821import com .fasterxml .jackson .core .io .JsonEOFException ;
1922import com .fasterxml .jackson .databind .JsonNode ;
2023import io .a2a .server .ExtendedAgentCard ;
24+ import io .a2a .server .ServerCallContext ;
25+ import io .a2a .server .auth .UnauthenticatedUser ;
26+ import io .a2a .server .auth .User ;
2127import io .a2a .server .requesthandlers .JSONRPCHandler ;
2228import io .a2a .server .util .async .Internal ;
2329import io .a2a .spec .AgentCard ;
@@ -78,9 +84,13 @@ public class A2AServerRoutes {
7884 @ Internal
7985 Executor executor ;
8086
87+ @ Inject
88+ Instance <CallContextFactory > callContextFactory ;
89+
8190 @ Route (path = "/" , methods = {Route .HttpMethod .POST }, consumes = {APPLICATION_JSON }, type = Route .HandlerType .BLOCKING )
8291 public void invokeJSONRPCHandler (@ Body String body , RoutingContext rc ) {
8392 boolean streaming = false ;
93+ ServerCallContext context = createCallContext (rc );
8494 JSONRPCResponse <?> nonStreamingResponse = null ;
8595 Multi <? extends JSONRPCResponse <?>> streamingResponse = null ;
8696 JSONRPCErrorResponse error = null ;
@@ -89,10 +99,10 @@ public void invokeJSONRPCHandler(@Body String body, RoutingContext rc) {
8999 if (isStreamingRequest (body )) {
90100 streaming = true ;
91101 StreamingJSONRPCRequest <?> request = Utils .OBJECT_MAPPER .readValue (body , StreamingJSONRPCRequest .class );
92- streamingResponse = processStreamingRequest (request );
102+ streamingResponse = processStreamingRequest (request , context );
93103 } else {
94104 NonStreamingJSONRPCRequest <?> request = Utils .OBJECT_MAPPER .readValue (body , NonStreamingJSONRPCRequest .class );
95- nonStreamingResponse = processNonStreamingRequest (request );
105+ nonStreamingResponse = processNonStreamingRequest (request , context );
96106 }
97107 } catch (JsonProcessingException e ) {
98108 error = handleError (e );
@@ -183,32 +193,34 @@ public void getAuthenticatedExtendedAgentCard(RoutingExchange re) {
183193 }
184194 }
185195
186- private JSONRPCResponse <?> processNonStreamingRequest (NonStreamingJSONRPCRequest <?> request ) {
187- if (request instanceof GetTaskRequest ) {
188- return jsonRpcHandler .onGetTask ((GetTaskRequest ) request );
189- } else if (request instanceof CancelTaskRequest ) {
190- return jsonRpcHandler .onCancelTask ((CancelTaskRequest ) request );
191- } else if (request instanceof SetTaskPushNotificationConfigRequest ) {
192- return jsonRpcHandler .setPushNotificationConfig ((SetTaskPushNotificationConfigRequest ) request );
193- } else if (request instanceof GetTaskPushNotificationConfigRequest ) {
194- return jsonRpcHandler .getPushNotificationConfig ((GetTaskPushNotificationConfigRequest ) request );
195- } else if (request instanceof SendMessageRequest ) {
196- return jsonRpcHandler .onMessageSend ((SendMessageRequest ) request );
197- } else if (request instanceof ListTaskPushNotificationConfigRequest ) {
198- return jsonRpcHandler .listPushNotificationConfig ((ListTaskPushNotificationConfigRequest ) request );
199- } else if (request instanceof DeleteTaskPushNotificationConfigRequest ) {
200- return jsonRpcHandler .deletePushNotificationConfig ((DeleteTaskPushNotificationConfigRequest ) request );
196+ private JSONRPCResponse <?> processNonStreamingRequest (
197+ NonStreamingJSONRPCRequest <?> request , ServerCallContext context ) {
198+ if (request instanceof GetTaskRequest req ) {
199+ return jsonRpcHandler .onGetTask (req , context );
200+ } else if (request instanceof CancelTaskRequest req ) {
201+ return jsonRpcHandler .onCancelTask (req , context );
202+ } else if (request instanceof SetTaskPushNotificationConfigRequest req ) {
203+ return jsonRpcHandler .setPushNotificationConfig (req , context );
204+ } else if (request instanceof GetTaskPushNotificationConfigRequest req ) {
205+ return jsonRpcHandler .getPushNotificationConfig (req , context );
206+ } else if (request instanceof SendMessageRequest req ) {
207+ return jsonRpcHandler .onMessageSend (req , context );
208+ } else if (request instanceof ListTaskPushNotificationConfigRequest req ) {
209+ return jsonRpcHandler .listPushNotificationConfig (req , context );
210+ } else if (request instanceof DeleteTaskPushNotificationConfigRequest req ) {
211+ return jsonRpcHandler .deletePushNotificationConfig (req , context );
201212 } else {
202213 return generateErrorResponse (request , new UnsupportedOperationError ());
203214 }
204215 }
205216
206- private Multi <? extends JSONRPCResponse <?>> processStreamingRequest (JSONRPCRequest <?> request ) {
217+ private Multi <? extends JSONRPCResponse <?>> processStreamingRequest (
218+ JSONRPCRequest <?> request , ServerCallContext context ) {
207219 Flow .Publisher <? extends JSONRPCResponse <?>> publisher ;
208- if (request instanceof SendStreamingMessageRequest ) {
209- publisher = jsonRpcHandler .onMessageSendStream (( SendStreamingMessageRequest ) request );
210- } else if (request instanceof TaskResubscriptionRequest ) {
211- publisher = jsonRpcHandler .onResubscribeToTask (( TaskResubscriptionRequest ) request );
220+ if (request instanceof SendStreamingMessageRequest req ) {
221+ publisher = jsonRpcHandler .onMessageSendStream (req , context );
222+ } else if (request instanceof TaskResubscriptionRequest req ) {
223+ publisher = jsonRpcHandler .onResubscribeToTask (req , context );
212224 } else {
213225 return Multi .createFrom ().item (generateErrorResponse (request , new UnsupportedOperationError ()));
214226 }
@@ -234,6 +246,42 @@ static void setStreamingMultiSseSupportSubscribedRunnable(Runnable runnable) {
234246 streamingMultiSseSupportSubscribedRunnable = runnable ;
235247 }
236248
249+ private ServerCallContext createCallContext (RoutingContext rc ) {
250+
251+ if (callContextFactory .isUnsatisfied ()) {
252+ User user ;
253+ if (rc .user () == null ) {
254+ user = UnauthenticatedUser .INSTANCE ;
255+ } else {
256+ user = new User () {
257+ @ Override
258+ public boolean isAuthenticated () {
259+ return rc .userContext ().authenticated ();
260+ }
261+
262+ @ Override
263+ public String getUsername () {
264+ return rc .user ().subject ();
265+ }
266+ };
267+ }
268+ Map <String , Object > state = new HashMap <>();
269+ // TODO Python's impl has
270+ // state['auth'] = request.auth
271+ // in jsonrpc_app.py. Figure out what this maps to in what Vert.X gives us
272+
273+ Map <String , String > headers = new HashMap <>();
274+ Set <String > headerNames = rc .request ().headers ().names ();
275+ headerNames .forEach (name -> headers .put (name , rc .request ().getHeader (name )));
276+ state .put ("headers" , headers );
277+
278+ return new ServerCallContext (user , state );
279+ } else {
280+ CallContextFactory builder = callContextFactory .get ();
281+ return builder .build (rc );
282+ }
283+ }
284+
237285 // Port of import io.quarkus.vertx.web.runtime.MultiSseSupport, which is considered internal API
238286 private static class MultiSseSupport {
239287
0 commit comments