org.jboss.netty.channel

## Interface ChannelHandler

All Known Subinterfaces:
  ChannelDownstreamHandler, ChannelUpstreamHandler, LifeCycleAwareChannelHandler

All Known Implementing Classes:
  AbstractTrafficShapingHandler, Base64Decoder, Base64Encoder, BlockingReadHandler, BufferedWriteHandler, ChannelTrafficShapingHandler, ChunkedWriteHandler, CompatibleMarshallingDecoder, CompatibleMarshallingEncoder, CompatibleObjectDecoder, CompatibleObjectEncoder, DelimiterBasedFrameDecoder, ExecutionHandler, FixedLengthFrameDecoder, FrameDecoder, GlobalTrafficShapingHandler, HttpChunkAggregator, HttpClientCodec, HttpContentCompressor, HttpContentDecoder, HttpContentDecompressor, HttpContentEncoder, HttpMessageDecoder, HttpMessageEncoder, HttpRequestDecoder, HttpRequestEncoder, HttpResponseDecoder, HttpResponseEncoder, HttpServerCodec, IdleStateAwareChannelHandler, IdleStateAwareChannelUpstreamHandler, IdleStateHandler, IpFilteringHandlerImpl, IpFilterRuleHandler, JdkZlibEncoder, LengthFieldBasedFrameDecoder, LengthFieldPrepender, LoggingHandler, MarshallingDecoder, MarshallingEncoder, ObjectDecoder, ObjectEncoder, OneIpFilterHandler, OneToOneDecoder, OneToOneEncoder, ProtobufDecoder, ProtobufEncoder, ProtobufVarint32FrameDecoder, ProtobufVarint32LengthFieldPrepender, ReadTimeoutHandler, ReplayingDecoder, RtspMessageDecoder, RtspMessageEncoder, RtspRequestDecoder, RtspRequestEncoder, RtspResponseDecoder, RtspResponseEncoder, SimpleChannelDownstreamHandler, SimpleChannelHandler, SimpleChannelUpstreamHandler, SpdyFrameCodec, SpdyFrameDecoder, SpdyFrameEncoder, SpdyHttpCodec, SpdyHttpDecoder, SpdyHttpEncoder, SpdySessionHandler, SslHandler, StringDecoder, StringEncoder, WebSocket00FrameDecoder, WebSocket00FrameEncoder, WebSocket08FrameDecoder, WebSocket08FrameEncoder, WebSocket13FrameDecoder, WebSocket13FrameEncoder, WebSocketFrameDecoder, WebSocketFrameEncoder, WriteTimeoutHandler, ZlibDecoder, ZlibEncoder

    public interface ChannelHandler

Handles or intercepts a `ChannelEvent`, and sends a `ChannelEvent` to the next handler in a `ChannelPipeline`.

### Sub-types

`ChannelHandler` itself does not provide any method. To handle a `ChannelEvent` you need to implement its sub-interfaces. There are two sub-interfaces which handles a received event, one for upstream events and the other for downstream events:

- `ChannelUpstreamHandler` handles and intercepts an upstream `ChannelEvent`.
- `ChannelDownstreamHandler` handles and intercepts a downstream `ChannelEvent`.

You will also find more detailed explanation from the documentation of each sub-interface on how an event is interpreted when it goes upstream and downstream respectively.

### The context object

A `ChannelHandler` is provided with a `ChannelHandlerContext` object. A `ChannelHandler` is supposed to interact with the `ChannelPipeline` it belongs to via a context object. Using the context object, the `ChannelHandler` can pass events upstream or downstream, modify the pipeline dynamically, or store the information (attachment) which is specific to the handler.

### State management

A `ChannelHandler` often needs to store some stateful information. The simplest and recommended approach is to use member variables:

     public class DataServerHandler extends SimpleChannelHandler {

         private boolean loggedIn;

         @Override
         public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
             Channel ch = e.getChannel();
             Object o = e.getMessage();
             if (o instanceof LoginMessage) {
                 authenticate((LoginMessage) o);
                 loggedIn = true;
             } else (o instanceof GetDataMessage) {
                 if (loggedIn) {
                     ch.write(fetchSecret((GetDataMessage) o));
                 } else {
                     fail();
                 }
             }
         }
         ...
     }

Because the handler instance has a state variable which is dedicated to one connection, you have to create a new handler instance for each new channel to avoid a race condition where a unauthenticated client can get the confidential information:

     // Create a new handler instance per channel.
     // See Bootstrap.setPipelineFactory(ChannelPipelineFactory).
     public class DataServerPipelineFactory implements ChannelPipelineFactory {
         public ChannelPipeline getPipeline() {
             return Channels.pipeline(new DataServerHandler());
         }
     }

#### Using an attachment

Although it's recommended to use member variables to store the state of a handler, for some reason you might not want to create many handler instances. In such a case, you can use an attachment which is provided by `ChannelHandlerContext`:

     @Sharable
     public class DataServerHandler extends SimpleChannelHandler {

         @Override
         public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
             Channel ch = e.getChannel();
             Object o = e.getMessage();
             if (o instanceof LoginMessage) {
                 authenticate((LoginMessage) o);
                 ctx.setAttachment(true);
             } else (o instanceof GetDataMessage) {
                 if (Boolean.TRUE.equals(ctx.getAttachment())) {
                     ch.write(fetchSecret((GetDataMessage) o));
                 } else {
                     fail();
                 }
             }
         }
         ...
     }

Now that the state of the handler is stored as an attachment, you can add the same handler instance to different pipelines:

     public class DataServerPipelineFactory implements ChannelPipelineFactory {

         private static final DataServerHandler SHARED = new DataServerHandler();

         public ChannelPipeline getPipeline() {
             return Channels.pipeline(SHARED);
         }
     }

#### Using a `ChannelLocal`

If you have a state variable which needs to be accessed either from other handlers or outside handlers, you can use `ChannelLocal`:

     public final class DataServerState {

         public static final ChannelLocal<Boolean> loggedIn = new ChannelLocal<>() {
             protected Boolean initialValue(Channel channel) {
                 return false;
             }
         }
         ...
     }

     @Sharable
     public class DataServerHandler extends SimpleChannelHandler {

         @Override
         public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
             Channel ch = e.getChannel();
             Object o = e.getMessage();
             if (o instanceof LoginMessage) {
                 authenticate((LoginMessage) o);
                 DataServerState.loggedIn.set(ch, true);
             } else (o instanceof GetDataMessage) {
                 if (DataServerState.loggedIn.get(ch)) {
                     ctx.getChannel().write(fetchSecret((GetDataMessage) o));
                 } else {
                     fail();
                 }
             }
         }
         ...
     }

     // Print the remote addresses of the authenticated clients:
     ChannelGroup allClientChannels = ...;
     for (Channel ch: allClientChannels) {
         if (DataServerState.loggedIn.get(ch)) {
             System.out.println(ch.getRemoteAddress());
         }
     }

#### The `@Sharable` annotation

In the examples above which used an attachment or a `ChannelLocal`, you might have noticed the `@Sharable` annotation.

If a `ChannelHandler` is annotated with the `@Sharable` annotation, it means you can create an instance of the handler just once and add it to one or more `ChannelPipeline`s multiple times without a race condition.

If this annotation is not specified, you have to create a new handler instance every time you add it to a pipeline because it has unshared state such as member variables.

This annotation is provided for documentation purpose, just like the JCIP annotations.

### Additional resources worth reading

Please refer to the `ChannelEvent` and `ChannelPipeline` to find out what a upstream event and a downstream event are, what fundamental differences they have, and how they flow in a pipeline.

### Nested Class Summary

Nested Classes
`static interface` `ChannelHandler.Sharable` Indicates that the same instance of the annotated `ChannelHandler` can be added to one or more `ChannelPipeline`s multiple times without a race condition.