sun.com/blueprints/corej2eepatterns/Patterns/InterceptingFilter.html">Intercepting Filter pattern to give a user full control over how an event is handled and how the {@link ChannelHandler}s in the pipeline interact with each other.
Creation of a pipeline
For each new channel, a new pipeline iscreated and attached to the channel. Once attached, the coupling between the channel and the pipeline is permanent; the channel cannot attach another pipeline to it nor detach the current pipeline from it. All of this is handled for you and you not need to take care of this.
How an event flows in a pipeline
The following diagram describes how I/O is processed by {@link ChannelHandler}s in a {@link ChannelPipeline} typically.A I/O-operation can be handled by either a {@link ChannelInboundHandler}or a {@link ChannelOutboundHandler} and be forwarded to the closesthandler by calling either one of the methods defined in the {@link ChannelInboundInvoker} interface for inbound I/O or by oneof the methods defined in the {@link ChannelOutboundInvoker} interfacefor outbound I/O. {@link ChannelPipeline} extends both of them.
I/O Request via {@link Channel} or{@link ChannelHandlerContext}| +----------------------------------------------------+-----------------+ | ChannelPipeline | | | \|/ | | +----------------------+ +-----------+------------+ | | | Inbound Handler N | | Outbound Handler 1 | | | +----------+-----------+ +-----------+------------+ | | /|\ | | | | \|/ | | +----------+-----------+ +-----------+------------+ | | | Inbound Handler N-1 | | Outbound Handler 2 | | | +----------+-----------+ +-----------+------------+ | | /|\ . | | . . | | [ {@link ChannelInboundInvoker}] [ {@link ChannelOutboundInvoker}()] | | [ method call] [method call] | | . . | | . \|/ | | +----------+-----------+ +-----------+------------+ | | | Inbound Handler 2 | | Outbound Handler M-1 | | | +----------+-----------+ +-----------+------------+ | | /|\ | | | | \|/ | | +----------+-----------+ +-----------+------------+ | | | Inbound Handler 1 | | Outbound Handler M | | | +----------+-----------+ +-----------+------------+ | | /|\ | | +---------------+------------------------------------+-----------------+ | \|/ +---------------+------------------------------------+-----------------+ | | | | | [ Socket.read() ] [ Socket.write() ] | | | | Netty Internal I/O Threads (Transport Implementation) | +----------------------------------------------------------------------+
An upstream event is handled by the upstream handlers in the bottom-up direction as shown on the left side of the diagram. An upstream handler usually handles the inbound data generated by the I/O thread on the bottom of the diagram. The inbound data is often read from a remote peer via the actual input operation such as {@link InputStream#read(byte[])}. If an upstream event goes beyond the top upstream handler, it is discarded silently.
A downstream event is handled by the downstream handler in the top-down direction as shown on the right side of the diagram. A downstream handler usually generates or transforms the outbound traffic such as write requests. If a downstream event goes beyond the bottom downstream handler, it is handled by an I/O thread associated with the {@link Channel}. The I/O thread often performs the actual output operation such as {@link OutputStream#write(byte[])}.
For example, let us assume that we created the following pipeline:
{@link ChannelPipeline} p = ...;p.addLast("1", new InboundHandlerA()); p.addLast("2", new InboundHandlerB()); p.addLast("3", new OutboundHandlerA()); p.addLast("4", new OutboundHandlerB()); p.addLast("5", new InboundOutboundHandlerX());
In the example above, the class whose name starts with {@code Upstream} meansit is an upstream handler. The class whose name starts with {@code Downstream} means it is a downstream handler.
In the given example configuration, the handler evaluation order is 1, 2, 3, 4, 5 when an event goes upstream. When an event goes downstream, the order is 5, 4, 3, 2, 1. On top of this principle, {@link ChannelPipeline} skipsthe evaluation of certain handlers to shorten the stack depth:
- 3 and 4 don't implement {@link ChannelInboundHandler}, and therefore the actual evaluation order of an upstream event will be: 1, 2, and 5.
- 1, 2, and 5 don't implement {@link ChannelOutboundHandler}, and therefore the actual evaluation order of a downstream event will be: 4 and 3.
- If 5 implements both {@link ChannelInboundHandler} and {@link ChannelOutboundHandler}, the evaluation order of an upstream and a downstream event could be 125 and 543 respectively.
Building a pipeline
A user is supposed to have one or more {@link ChannelHandler}s in a pipeline to receive I/O events (e.g. read) and to request I/O operations (e.g. write and close). For example, a typical server will have the following handlers in each channel's pipeline, but your mileage may vary depending on the complexity and characteristics of the protocol and business logic:
- Protocol Decoder - translates binary data (e.g. {@link ByteBuf}) into a Java object.
- Protocol Encoder - translates a Java object into binary data.
- ExecutionHandler - applies a thread model.
- Business Logic Handler - performs the actual business logic (e.g. database access).
and it could be represented as shown in the following example:
{@link ChannelPipeline} pipeline = ...;pipeline.addLast("decoder", new MyProtocolDecoder()); pipeline.addLast("encoder", new MyProtocolEncoder()); pipeline.addLast("executor", new ExecutionHandler(...)); pipeline.addLast("handler", new MyBusinessLogicHandler());
Thread safety
A {@link ChannelHandler} can be added or removed at any time because a{@link ChannelPipeline} is thread safe. For example, you can insert anencryption handler when sensitive information is about to be exchanged, and remove it after the exchange.