2020import java .util .Arrays ;
2121import java .util .Map ;
2222import java .util .Objects ;
23- import java .util .concurrent .ConcurrentHashMap ;
24- import java .util .concurrent .ExecutorService ;
25- import java .util .concurrent .Executors ;
26- import java .util .concurrent .Future ;
23+ import java .util .concurrent .*;
2724import java .util .concurrent .atomic .AtomicBoolean ;
2825import java .util .concurrent .atomic .AtomicInteger ;
2926import java .util .concurrent .atomic .AtomicReference ;
@@ -317,9 +314,9 @@ protected boolean handleDataSourceSockets() {
317314 return dataAvailable ;
318315 }
319316
320- protected <R > ThePromisedFuture <R , ? > newRequestFuture (final URI endpoint , final Class <R > requestedDomainObjType , final Command requestType , final String requestId ) {
317+ protected <R , C > ThePromisedFuture <R , C > newRequestFuture (final URI endpoint , final Class <R > requestedDomainObjType , final Command requestType , final String requestId ) {
321318 FilterRegistry .checkClassForNewFilters (requestedDomainObjType );
322- final ThePromisedFuture <R , ? > requestFuture = new ThePromisedFuture <>(endpoint , requestedDomainObjType , null , requestType , requestId , null );
319+ final ThePromisedFuture <R , C > requestFuture = new ThePromisedFuture <>(endpoint , requestedDomainObjType , null , requestType , requestId , null );
323320 final Object oldEntry = requests .put (requestId , requestFuture );
324321 assert oldEntry == null : "requestID '" + requestId + "' already present in requestFutureMap" ;
325322 return requestFuture ;
@@ -367,19 +364,19 @@ protected void internalEventHandler(final RingBufferEvent event, final long sequ
367364 replyDomainObject = ioClassSerialiser .deserialiseObject (reqClassType );
368365 ioClassSerialiser .setDataBuffer (byteBuffer ); // allow received byte array to be released
369366 }
370- if (notifyFuture ) {
371- domainObject .future .castAndSetReply (replyDomainObject ); // notify callback
367+ final Object contextObject ;
368+ if (domainObject .future .contextType == null || domainObject .future .contextType .equals (Map .class )) {
369+ contextObject = QueryParameterParser .getMap (endpointURI .getQuery ());
370+ } else {
371+ contextObject = QueryParameterParser .parseQueryParameter (domainObject .future .contextType , endpointURI .getQuery ());
372372 }
373373 if (domainObject .future .listener != null ) {
374374 final var finalDomainObj = replyDomainObject ;
375- final Object contextObject ;
376- if (domainObject .future .contextType == null ) {
377- contextObject = QueryParameterParser .getMap (endpointURI .getQuery ());
378- } else {
379- contextObject = QueryParameterParser .parseQueryParameter (domainObject .future .contextType , endpointURI .getQuery ());
380- }
381375 executor .submit (() -> domainObject .future .notifyListener (finalDomainObj , contextObject )); // NOPMD - threads are ok, not a webapp
382376 }
377+ if (notifyFuture ) {
378+ domainObject .future .castAndSetReplyWithContext (replyDomainObject , contextObject ); // notify callback
379+ }
383380 } catch (Exception e ) { // NOPMD: exception is forwarded to client
384381 final var sw = new StringWriter ();
385382 final var pw = new PrintWriter (sw );
@@ -453,18 +450,18 @@ private Client() { // accessed via outer class method
453450 clientSocket .connect (inprocCtrl );
454451 }
455452
456- public <R , C > Future < R > get (URI endpoint , final C requestContext , final Class <R > requestedDomainObjType , final RbacProvider ... rbacProvider ) {
453+ public <R , C > ThePromisedFuture < R , C > get (URI endpoint , final C requestContext , final Class <R > requestedDomainObjType , final RbacProvider ... rbacProvider ) {
457454 final String requestId = clientId + internalReqIdGenerator .incrementAndGet ();
458455 final URI endpointQuery = getEndpointQuery (endpoint , requestContext );
459- final ThePromisedFuture <R , ? > rThePromisedFuture = newRequestFuture (endpointQuery , requestedDomainObjType , Command .GET_REQUEST , requestId );
456+ final ThePromisedFuture <R , C > rThePromisedFuture = newRequestFuture (endpointQuery , requestedDomainObjType , Command .GET_REQUEST , requestId );
460457 request (requestId , Command .GET_REQUEST , endpointQuery , null , requestContext , rbacProvider );
461458 return rThePromisedFuture ;
462459 }
463460
464- public <R , C > Future < R > set (final URI endpoint , final R requestBody , final C requestContext , final Class <R > requestedDomainObjType , final RbacProvider ... rbacProvider ) {
461+ public <R , C > ThePromisedFuture < R , C > set (final URI endpoint , final R requestBody , final C requestContext , final Class <R > requestedDomainObjType , final RbacProvider ... rbacProvider ) {
465462 final String requestId = clientId + internalReqIdGenerator .incrementAndGet ();
466463 final URI endpointQuery = getEndpointQuery (endpoint , requestContext );
467- final ThePromisedFuture <R , ? > rThePromisedFuture = newRequestFuture (endpointQuery , requestedDomainObjType , Command .SET_REQUEST , requestId );
464+ final ThePromisedFuture <R , C > rThePromisedFuture = newRequestFuture (endpointQuery , requestedDomainObjType , Command .SET_REQUEST , requestId );
468465 request (requestId , Command .SET_REQUEST , endpointQuery , requestBody , requestContext , rbacProvider );
469466 return rThePromisedFuture ;
470467 }
@@ -551,8 +548,9 @@ private <R, C> void request(final String requestId, final Command requestType, f
551548 }
552549 }
553550
554- protected static class ThePromisedFuture <R , C > extends CustomFuture <R > { // NOPMD - no need for setters/getters here
551+ public static class ThePromisedFuture <R , C > extends CustomFuture <R > { // NOPMD - no need for setters/getters here
555552 private final URI endpoint ;
553+ private C replyContext ;
556554 private final Class <R > requestedDomainObjType ;
557555 private final Class <C > contextType ;
558556 private final Command requestType ;
@@ -586,10 +584,12 @@ public String getInternalRequestID() {
586584 }
587585
588586 public void notifyListener (final Object obj , final Object contextObject ) {
589- if (obj == null || !requestedDomainObjType .isAssignableFrom (obj .getClass ()) || ! contextType . isAssignableFrom ( contextObject . getClass ()) ) {
587+ if (obj == null || !requestedDomainObjType .isAssignableFrom (obj .getClass ())) {
590588 LOGGER .atError ().addArgument (requestedDomainObjType .getName ()).addArgument (obj == null ? "null" : obj .getClass ().getName ()).log ("Got wrong type for notification, got {} expected {}" );
589+ } else if (contextType != null && !contextType .isAssignableFrom (contextObject .getClass ())) {
590+ LOGGER .atError ().addArgument (contextObject .getClass ().getName ()).addArgument (contextType .getName ()).log ("Got wrong context type for notification, got {} expected {}" );
591591 } else {
592- //noinspection unchecked - cast is checked dynamically
592+ // noinspection unchecked - cast is checked dynamically
593593 listener .dataUpdate ((R ) obj , (C ) contextObject ); // NOPMD NOSONAR - cast is checked before implicitly
594594 }
595595 }
@@ -598,6 +598,17 @@ public void notifyListener(final Object obj, final Object contextObject) {
598598 protected void castAndSetReply (final Object newValue ) {
599599 this .setReply ((R ) newValue );
600600 }
601+
602+ @ SuppressWarnings ("unchecked" )
603+ protected void castAndSetReplyWithContext (final Object newValue , final Object contextObject ) {
604+ this .replyContext = (C ) contextObject ;
605+ this .setReply ((R ) newValue );
606+ }
607+
608+ public C getReplyContext () throws ExecutionException , InterruptedException {
609+ super .get ();
610+ return this .replyContext ;
611+ }
601612 }
602613
603614 protected static class InternalDomainObject {
0 commit comments