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
    Modifier and Type | Interface and Description
    --- | ---
    `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.

Copyright © 2008-2012 The Netty Project. All Rights Reserved.