Class GrpcBidiStreamHandler
- All Implemented Interfaces:
io.netty.channel.ChannelHandler,io.netty.channel.ChannelInboundHandler
@Sharable --
holds per-stream state (the incremental frame decoder, finished guard).
Phase 3b behaviour (rule-driven via GrpcBidiResponse):
- On
Http2HeadersFrame: applies the top-level action delay (if configured) before writing the initial response HEADERS (:status=200,content-type=application/grpc, plus any configured headers from the GrpcBidiResponse,endStream=false). Then writes any EAGER messages from the response, honouring per-messageGrpcStreamMessage.getDelay()via event-loop scheduling (messages are chained so ordering is preserved and the trailing grpc-status is written only after all scheduled messages complete). - On
Http2DataFrame: feeds content bytes toIncrementalGrpcFrameDecoder; for each complete inbound message, converts to JSON via the converter, evaluates rules in order (first match emits its responses as DATA frames). If no rule matches, no response is emitted. If the frame hasendStream=true, callsfinish(ChannelHandlerContext). finish(): writes trailing HEADERS with configured grpc-status andendStream=true. Guarded to run at most once.
The handler supports two modes:
- Phase 3b (GrpcBidiResponse-driven): Constructed with a
GrpcBidiResponseconfig; eager messages, rules, status, and headers come from the config. - Phase 3a (legacy responder function): Constructed with a
Functionresponder for backward compatibility with existing tests.
Flow control: the channel's autoRead is set to false when this handler is
added; after processing each inbound frame, ctx.read() is called to request
the next frame. If the decoder's buffer cap is exceeded, a RESOURCE_EXHAUSTED trailing
status is written and the stream is finished.
Error handling: exceptions during channelRead are caught and result in an INTERNAL grpc-status trailer, never an uncaught exception propagating up the pipeline.
-
Nested Class Summary
Nested classes/interfaces inherited from interface io.netty.channel.ChannelHandler
io.netty.channel.ChannelHandler.Sharable -
Constructor Summary
ConstructorsConstructorDescriptionGrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, Function<String, List<String>> responder) Phase 3a constructor: function-based responder (backward compatible).GrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config) Phase 3b constructor: GrpcBidiResponse-driven (without completion callback).GrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback) Phase 3b constructor: GrpcBidiResponse-driven with completion callback.GrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback, Configuration configuration, String inboundStreamId) Phase 3b constructor: GrpcBidiResponse-driven with completion callback and inbound breakpoints.GrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback, Configuration configuration, String inboundStreamId, WebSocketClientRegistry webSocketClientRegistry) Deprecated.use the constructor that accepts inboundBreakpointClientId and inboundBreakpointId from the outer caller to avoid mis-routing across clientsGrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback, Configuration configuration, String inboundStreamId, WebSocketClientRegistry webSocketClientRegistry, String inboundBreakpointClientId, String inboundBreakpointId) Phase 3b constructor: GrpcBidiResponse-driven with completion callback, inbound breakpoints, per-server WebSocket registry, and pre-resolved breakpoint identity from the outer caller. -
Method Summary
Modifier and TypeMethodDescriptionvoidchannelInactive(io.netty.channel.ChannelHandlerContext ctx) Handles channel deactivation (client disconnect, connection closed, abandoned stream).voidchannelRead(io.netty.channel.ChannelHandlerContext ctx, Object msg) voidexceptionCaught(io.netty.channel.ChannelHandlerContext ctx, Throwable cause) voidhandlerAdded(io.netty.channel.ChannelHandlerContext ctx) Methods inherited from class io.netty.channel.ChannelInboundHandlerAdapter
channelActive, channelReadComplete, channelRegistered, channelUnregistered, channelWritabilityChanged, userEventTriggeredMethods inherited from class io.netty.channel.ChannelHandlerAdapter
ensureNotSharable, handlerRemoved, isSharableMethods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface io.netty.channel.ChannelHandler
handlerRemoved
-
Constructor Details
-
GrpcBidiStreamHandler
public GrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, Function<String, List<String>> responder) Phase 3a constructor: function-based responder (backward compatible).- Parameters:
methodDescriptor- the resolved gRPC method descriptorconverter- JSON/protobuf converter for the method's message typesresponder- maps an inbound message JSON string to a list of response JSON strings; for 3a the default is echo: returns[inboundJson]
-
GrpcBidiStreamHandler
public GrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config) Phase 3b constructor: GrpcBidiResponse-driven (without completion callback).- Parameters:
methodDescriptor- the resolved gRPC method descriptorconverter- JSON/protobuf converter for the method's message typesconfig- the GrpcBidiResponse configuration from the matched expectation
-
GrpcBidiStreamHandler
public GrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback) Phase 3b constructor: GrpcBidiResponse-driven with completion callback. The completion callback is invoked exactly once when the stream finishes (or errors), clearingresponseInProgresson the matched expectation.- Parameters:
methodDescriptor- the resolved gRPC method descriptorconverter- JSON/protobuf converter for the method's message typesconfig- the GrpcBidiResponse configuration from the matched expectationcompletionCallback- invoked once on stream finish to clear responseInProgress
-
GrpcBidiStreamHandler
public GrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback, Configuration configuration, String inboundStreamId) Phase 3b constructor: GrpcBidiResponse-driven with completion callback and inbound breakpoints.- Parameters:
methodDescriptor- the resolved gRPC method descriptorconverter- JSON/protobuf converter for the method's message typesconfig- the GrpcBidiResponse configuration from the matched expectationcompletionCallback- invoked once on stream finish to clear responseInProgressconfiguration- the active server configuration (null to disable inbound breakpoints)inboundStreamId- the stream ID for inbound breakpoints (null to disable)
-
GrpcBidiStreamHandler
public GrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback, Configuration configuration, String inboundStreamId, WebSocketClientRegistry webSocketClientRegistry) Deprecated.use the constructor that accepts inboundBreakpointClientId and inboundBreakpointId from the outer caller to avoid mis-routing across clientsPhase 3b constructor: GrpcBidiResponse-driven with completion callback, inbound breakpoints, and per-server WebSocket registry. Performs its own findMatch for inbound breakpoints. -
GrpcBidiStreamHandler
public GrpcBidiStreamHandler(com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback, Configuration configuration, String inboundStreamId, WebSocketClientRegistry webSocketClientRegistry, String inboundBreakpointClientId, String inboundBreakpointId) Phase 3b constructor: GrpcBidiResponse-driven with completion callback, inbound breakpoints, per-server WebSocket registry, and pre-resolved breakpoint identity from the outer caller.- Parameters:
methodDescriptor- the resolved gRPC method descriptorconverter- JSON/protobuf converter for the method's message typesconfig- the GrpcBidiResponse configuration from the matched expectationcompletionCallback- invoked once on stream finish to clear responseInProgressconfiguration- the active server configuration (null to disable inbound breakpoints)inboundStreamId- the stream ID for inbound breakpoints (null to disable)webSocketClientRegistry- the per-server WS registry for callback dispatch (null to disable)inboundBreakpointClientId- the matched inbound breakpoint's owning clientId (from outer caller)inboundBreakpointId- the matched inbound breakpoint's id (from outer caller)
-
-
Method Details
-
handlerAdded
public void handlerAdded(io.netty.channel.ChannelHandlerContext ctx) - Specified by:
handlerAddedin interfaceio.netty.channel.ChannelHandler- Overrides:
handlerAddedin classio.netty.channel.ChannelHandlerAdapter
-
channelRead
- Specified by:
channelReadin interfaceio.netty.channel.ChannelInboundHandler- Overrides:
channelReadin classio.netty.channel.ChannelInboundHandlerAdapter
-
exceptionCaught
- Specified by:
exceptionCaughtin interfaceio.netty.channel.ChannelHandler- Specified by:
exceptionCaughtin interfaceio.netty.channel.ChannelInboundHandler- Overrides:
exceptionCaughtin classio.netty.channel.ChannelInboundHandlerAdapter
-
channelInactive
Handles channel deactivation (client disconnect, connection closed, abandoned stream). If the stream has not already finished viafinish(io.netty.channel.ChannelHandlerContext)orwriteTrailer(io.netty.channel.ChannelHandlerContext, org.mockserver.grpc.GrpcStatusMapper.GrpcStatusCode, java.lang.String), the completion callback is invoked to clearresponseInProgresson the matched expectation. This prevents a times-limited expectation from being stuck forever when a bidi stream is abandoned without a clean END_STREAM.The callback is self-guarded by
callbackInvoked(AtomicBoolean CAS), so it runs exactly once across all terminal paths: normal finish, error trailer, channel inactive, and exception caught.Also evicts any held inbound breakpoint frames to prevent resource leaks and hanging futures.
- Specified by:
channelInactivein interfaceio.netty.channel.ChannelInboundHandler- Overrides:
channelInactivein classio.netty.channel.ChannelInboundHandlerAdapter- Throws:
Exception
-