55import java .util .Optional ;
66import java .util .concurrent .atomic .AtomicBoolean ;
77import java .util .function .Consumer ;
8- import java .util .function .Supplier ;
8+ import java .util .function .Function ;
99
1010import jakarta .enterprise .context .ApplicationScoped ;
1111import jakarta .enterprise .inject .spi .Prioritized ;
1212import jakarta .inject .Inject ;
1313
1414import org .jboss .logging .Logger ;
1515
16+ import io .grpc .ForwardingServerCall ;
1617import io .grpc .Metadata ;
1718import io .grpc .ServerCall ;
1819import io .grpc .ServerCallHandler ;
1920import io .grpc .ServerInterceptor ;
21+ import io .grpc .Status ;
2022import io .grpc .StatusException ;
2123import io .quarkus .grpc .ExceptionHandlerProvider ;
2224import io .quarkus .grpc .GlobalInterceptor ;
@@ -54,15 +56,27 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, Re
5456 }
5557 }
5658
57- private <ReqT , RespT > Supplier < ServerCall .Listener <ReqT >> nextCall (ServerCall <ReqT , RespT > call ,
59+ private <ReqT , RespT > Function < Runnable , ServerCall .Listener <ReqT >> nextCall (ServerCall <ReqT , RespT > call ,
5860 Metadata headers ,
5961 ServerCallHandler <ReqT , RespT > next ) {
6062 // Must be sure to call next.startCall on the right context
6163 io .grpc .Context current = io .grpc .Context .current ();
62- return () -> {
64+ return onClose -> {
6365 io .grpc .Context previous = current .attach ();
6466 try {
65- return next .startCall (call , headers );
67+ var forwardingCall = new ForwardingServerCall <ReqT , RespT >() {
68+ @ Override
69+ protected ServerCall <ReqT , RespT > delegate () {
70+ return call ;
71+ }
72+
73+ @ Override
74+ public void close (Status status , Metadata trailers ) {
75+ onClose .run ();
76+ super .close (status , trailers );
77+ }
78+ };
79+ return next .startCall (forwardingCall , headers );
6680 } finally {
6781 current .detach (previous );
6882 }
@@ -77,31 +91,35 @@ public int getPriority() {
7791 static class ListenedOnDuplicatedContext <ReqT , RespT > extends ServerCall .Listener <ReqT > {
7892
7993 private final Context context ;
80- private final Supplier < ServerCall .Listener <ReqT >> supplier ;
94+ private final Function < Runnable , ServerCall .Listener <ReqT >> listenerCreator ;
8195 private final ExceptionHandlerProvider ehp ;
8296 private final ServerCall <ReqT , RespT > call ;
83- private ServerCall .Listener <ReqT > delegate ;
97+ private volatile ServerCall .Listener <ReqT > delegate ;
8498
8599 private final AtomicBoolean closed = new AtomicBoolean ();
86100
87101 public ListenedOnDuplicatedContext (
88102 ExceptionHandlerProvider ehp ,
89- ServerCall <ReqT , RespT > call , Supplier < ServerCall .Listener <ReqT >> supplier , Context context ) {
103+ ServerCall <ReqT , RespT > call , Function < Runnable , ServerCall .Listener <ReqT >> listenerCreator , Context context ) {
90104 this .ehp = ehp ;
91105 this .context = context ;
92- this .supplier = supplier ;
106+ this .listenerCreator = listenerCreator ;
93107 this .call = call ;
94108 }
95109
96- private synchronized ServerCall .Listener <ReqT > getDelegate () {
97- if (delegate == null ) {
98- try {
99- delegate = supplier .get ();
100- } catch (Throwable t ) {
101- // If the interceptor supplier throws an exception, catch it, and close the call.
102- log .warn ("Unable to retrieve gRPC Server call listener, see the cause below." );
103- close (t );
104- return null ;
110+ private ServerCall .Listener <ReqT > getDelegate () {
111+ if (delegate == null && !closed .get ()) {
112+ synchronized (this ) {
113+ if (delegate == null && !closed .get ()) {
114+ try {
115+ delegate = listenerCreator .apply (() -> closed .set (true ));
116+ } catch (Throwable t ) {
117+ // If the interceptor supplier throws an exception, catch it, and close the call.
118+ log .warn ("Unable to retrieve gRPC Server call listener, see the cause below." );
119+ close (t );
120+ return null ;
121+ }
122+ }
105123 }
106124 }
107125 return delegate ;
0 commit comments