1
votes

I'm writing a netty TCP server that must encode the response based on a responseType value in the request, for example returning Protobuf or JSON. What is the suggested way to implement this?


Our server has a pipeline with a decoder, encoder, and handler.

pipeline.addLast(new RequestDecoder<Request>())
pipeline.addLast(new ResponseEncoder<Response>())
pipeline.addLast(new Handler<Request, Response>())

I considered using the Decoder to add the correct encoder to the pipeline, like this

pipeline.addLast(new RequestDecoder<Request>())
pipeline.addLast(new ResponseEncoder<Response>())
pipeline.addLast(new Handler<Request, Response>())

class RequestDecoder<Request> {
  public void decode(...) {
    if (request.responseType().equals("protobuf")) {
      ch.pipeline().replace(ResponseEncoder.class, "protobuf", new ProtobufResponseEncoder<Response>());
    } else {
      ch.pipeline().replace(ResponseEncoder.class, "protobuf", new JsonResponseEncoder<Response>());
    }
  }
}

This appears to work but is it correct? The ChannelHandler docs lead me to this design.

A ChannelHandler can be added or removed at any time because a ChannelPipeline is thread safe. For example, you can insert an encryption handler when sensitive information is about to be exchanged, and remove it after the exchange.

The channel may be thread safe but will a channel handle requests serially? If not, if it starts a second request before finishing the first, then will the response for the first request use the encoder set by the second?


Alternatively I could wrap Request with a Protocol object RequestDecoder<Protocol<Request>>, but how would I forward the unwrapped Request to Handler?

1

1 Answers

0
votes

The channel may be thread safe but will a channel handle requests serially?

Netty does not understand the concept of a request/response inherently on a channel unless you add a handler that understands your protocol. In your case it is the encoder/decoder you added. Netty will read data from a channel and send it on the pipeline in the order it is available. Ordering beyond that is as done by the handlers, eg: a handler can decide to asynchronously process these messages and then write them out of order.

If not, if it starts a second request before finishing the first, then will the response for the first request use the encoder set by the second?

Yes if the request/responses are inter-leaved you should not modify the pipeline assuming they are ordered.

In your case, I would suggest having both handlers in the pipeline and let them process the message conditionally otherwise pass it through the pipeline. Alternatively, you can have a single handler that encode messages based on the type.