org.jboss.netty.channel

## Interface ChannelPipeline

- All Known Implementing Classes:
    DefaultChannelPipeline, StaticChannelPipeline

      public interface ChannelPipeline

  A list of `ChannelHandler`s which handles or intercepts `ChannelEvent`s of a `Channel`. `ChannelPipeline` implements an advanced form of the Intercepting Filter pattern to give a user full control over how an event is handled and how the `ChannelHandler`s in the pipeline interact with each other.

  ### Creation of a pipeline

  For each new channel, a new pipeline must be created 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.

  The recommended way to create a new pipeline is to use the helper methods in `Channels` rather than calling an individual implementation's constructor:

       import static org.jboss.netty.channel.Channels.*;
       ChannelPipeline pipeline = pipeline(); // same with Channels.pipeline()

  ### How an event flows in a pipeline

  The following diagram describes how `ChannelEvent`s are processed by `ChannelHandler`s in a `ChannelPipeline` typically. A `ChannelEvent` can be handled by either a `ChannelUpstreamHandler` or a `ChannelDownstreamHandler` and be forwarded to the closest handler by calling `ChannelHandlerContext.sendUpstream(ChannelEvent)` or `ChannelHandlerContext.sendDownstream(ChannelEvent)`. The meaning of the event is interpreted somewhat differently depending on whether it is going upstream or going downstream. Please refer to `ChannelEvent` for more information.

                                             I/O Request
                                           via Channel or
                                       ChannelHandlerContext
                                                 |
        +----------------------------------------+---------------+
        |                  ChannelPipeline       |               |
        |                                       \|/              |
        |  +----------------------+  +-----------+------------+  |
        |  | Upstream Handler  N  |  | Downstream Handler  1  |  |
        |  +----------+-----------+  +-----------+------------+  |
        |            /|\                         |               |
        |             |                         \|/              |
        |  +----------+-----------+  +-----------+------------+  |
        |  | Upstream Handler N-1 |  | Downstream Handler  2  |  |
        |  +----------+-----------+  +-----------+------------+  |
        |            /|\                         .               |
        |             .                          .               |
        |     [ sendUpstream() ]        [ sendDownstream() ]     |
        |     [ + INBOUND data ]        [ + OUTBOUND data  ]     |
        |             .                          .               |
        |             .                         \|/              |
        |  +----------+-----------+  +-----------+------------+  |
        |  | Upstream Handler  2  |  | Downstream Handler M-1 |  |
        |  +----------+-----------+  +-----------+------------+  |
        |            /|\                         |               |
        |             |                         \|/              |
        |  +----------+-----------+  +-----------+------------+  |
        |  | Upstream Handler  1  |  | Downstream 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 `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 `Channel`. The I/O thread often performs the actual output operation such as `OutputStream.write(byte[])`.

  For example, let us assume that we created the following pipeline:

       ChannelPipeline p = Channels.pipeline();
       p.addLast("1", new UpstreamHandlerA());
       p.addLast("2", new UpstreamHandlerB());
       p.addLast("3", new DownstreamHandlerA());
       p.addLast("4", new DownstreamHandlerB());
       p.addLast("5", new UpstreamHandlerX());

  In the example above, the class whose name starts with `Upstream` means it is an upstream handler. The class whose name starts with `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, `ChannelPipeline` skips the evaluation of certain handlers to shorten the stack depth:

  - 3 and 4 don't implement `ChannelUpstreamHandler`, and therefore the actual evaluation order of an upstream event will be: 1, 2, and 5.
  - 1, 2, and 5 don't implement `ChannelDownstreamHandler`, and therefore the actual evaluation order of a downstream event will be: 4 and 3.
  - If 5 extended `SimpleChannelHandler` which implements both `ChannelUpstreamHandler` and `ChannelDownstreamHandler`, 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 `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:

  1. Protocol Decoder - translates binary data (e.g. `ChannelBuffer`) into a Java object.
  2. Protocol Encoder - translates a Java object into binary data.
  3. `ExecutionHandler` - applies a thread model.
  4. Business Logic Handler - performs the actual business logic (e.g. database access).
  and it could be represented as shown in the following example:

       ChannelPipeline pipeline = Channels.pipeline();
       pipeline.addLast("decoder", new MyProtocolDecoder());
       pipeline.addLast("encoder", new MyProtocolEncoder());
       pipeline.addLast("executor", new ExecutionHandler(
               new OrderedMemoryAwareThreadPoolExecutor(16, 1048576, 1048576)));
       pipeline.addLast("handler", new MyBusinessLogicHandler());

  ### Thread safety

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

  ### Pitfall

  Due to the internal implementation detail of the current default `ChannelPipeline`, the following code does not work as expected if `FirstHandler` is the last handler in the pipeline:

       public class FirstHandler extends SimpleChannelUpstreamHandler {

           @Override
           public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
               // Remove this handler from the pipeline,
               ctx.getPipeline().remove(this);
               // And let SecondHandler handle the current event.
               ctx.getPipeline().addLast("2nd", new SecondHandler());
               ctx.sendUpstream(e);
           }
       }

  To implement the expected behavior, you have to add `SecondHandler` before the removal or make sure there is at least one more handler between `FirstHandler` and `SecondHandler`.

- - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `void` | `addAfter(String baseName, String name, ChannelHandler handler)` Inserts a `ChannelHandler` after an existing handler of this pipeline.
    `void` | `addBefore(String baseName, String name, ChannelHandler handler)` Inserts a `ChannelHandler` before an existing handler of this pipeline.
    `void` | `addFirst(String name, ChannelHandler handler)` Inserts a `ChannelHandler` at the first position of this pipeline.
    `void` | `addLast(String name, ChannelHandler handler)` Appends a `ChannelHandler` at the last position of this pipeline.
    `void` | `attach(Channel channel, ChannelSink sink)` Attaches this pipeline to the specified `Channel` and `ChannelSink`.
    `ChannelFuture` | `execute(Runnable task)` Schedules the specified task to be executed in the I/O thread associated with this pipeline's `Channel`.
    `<T extends ChannelHandler> T` | `get(Class<T> handlerType)` Returns the `ChannelHandler` of the specified type in this pipeline.
    `ChannelHandler` | `get(String name)` Returns the `ChannelHandler` with the specified name in this pipeline.
    `Channel` | `getChannel()` Returns the `Channel` that this pipeline is attached to.
    `ChannelHandlerContext` | `getContext(ChannelHandler handler)` Returns the context object of the specified `ChannelHandler` in this pipeline.
    `ChannelHandlerContext` | `getContext(Class<? extends ChannelHandler> handlerType)` Returns the context object of the `ChannelHandler` of the specified type in this pipeline.
    `ChannelHandlerContext` | `getContext(String name)` Returns the context object of the `ChannelHandler` with the specified name in this pipeline.
    `ChannelHandler` | `getFirst()` Returns the first `ChannelHandler` in this pipeline.
    `ChannelHandler` | `getLast()` Returns the last `ChannelHandler` in this pipeline.
    `List<String>` | `getNames()` Returns the `List` of the handler names.
    `ChannelSink` | `getSink()` Returns the `ChannelSink` that this pipeline is attached to.
    `boolean` | `isAttached()` Returns `true` if and only if this pipeline is attached to a `Channel`.
    `void` | `remove(ChannelHandler handler)` Removes the specified `ChannelHandler` from this pipeline.
    `<T extends ChannelHandler> T` | `remove(Class<T> handlerType)` Removes the `ChannelHandler` of the specified type from this pipeline
    `ChannelHandler` | `remove(String name)` Removes the `ChannelHandler` with the specified name from this pipeline.
    `ChannelHandler` | `removeFirst()` Removes the first `ChannelHandler` in this pipeline.
    `ChannelHandler` | `removeLast()` Removes the last `ChannelHandler` in this pipeline.
    `void` | `replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler)` Replaces the specified `ChannelHandler` with a new handler in this pipeline.
    `<T extends ChannelHandler> T` | `replace(Class<T> oldHandlerType, String newName, ChannelHandler newHandler)` Replaces the `ChannelHandler` of the specified type with a new handler in this pipeline.
    `ChannelHandler` | `replace(String oldName, String newName, ChannelHandler newHandler)` Replaces the `ChannelHandler` of the specified name with a new handler in this pipeline.
    `void` | `sendDownstream(ChannelEvent e)` Sends the specified `ChannelEvent` to the last `ChannelDownstreamHandler` in this pipeline.
    `void` | `sendUpstream(ChannelEvent e)` Sends the specified `ChannelEvent` to the first `ChannelUpstreamHandler` in this pipeline.
    `Map<String,ChannelHandler>` | `toMap()` Converts this pipeline into an ordered `Map` whose keys are handler names and whose values are handlers.

- - ### Method Detail

    - #### addFirst

          void addFirst(String name,
                      ChannelHandler handler)

      Inserts a `ChannelHandler` at the first position of this pipeline.
      Parameters:
        `name` - the name of the handler to insert first
        `handler` - the handler to insert first
      Throws:
        `IllegalArgumentException` - if there's an entry with the same name already in the pipeline
        `NullPointerException` - if the specified name or handler is `null`

    - #### addLast

          void addLast(String name,
                     ChannelHandler handler)

      Appends a `ChannelHandler` at the last position of this pipeline.
      Parameters:
        `name` - the name of the handler to append
        `handler` - the handler to append
      Throws:
        `IllegalArgumentException` - if there's an entry with the same name already in the pipeline
        `NullPointerException` - if the specified name or handler is `null`

    - #### addBefore

          void addBefore(String baseName,
                       String name,
                       ChannelHandler handler)

      Inserts a `ChannelHandler` before an existing handler of this pipeline.
      Parameters:
        `baseName` - the name of the existing handler
        `name` - the name of the handler to insert before
        `handler` - the handler to insert before
      Throws:
        `NoSuchElementException` - if there's no such entry with the specified `baseName`
        `IllegalArgumentException` - if there's an entry with the same name already in the pipeline
        `NullPointerException` - if the specified baseName, name, or handler is `null`

    - #### addAfter

          void addAfter(String baseName,
                      String name,
                      ChannelHandler handler)

      Inserts a `ChannelHandler` after an existing handler of this pipeline.
      Parameters:
        `baseName` - the name of the existing handler
        `name` - the name of the handler to insert after
        `handler` - the handler to insert after
      Throws:
        `NoSuchElementException` - if there's no such entry with the specified `baseName`
        `IllegalArgumentException` - if there's an entry with the same name already in the pipeline
        `NullPointerException` - if the specified baseName, name, or handler is `null`

    - #### remove

          void remove(ChannelHandler handler)

      Removes the specified `ChannelHandler` from this pipeline.
      Throws:
        `NoSuchElementException` - if there's no such handler in this pipeline
        `NullPointerException` - if the specified handler is `null`

    - #### remove

          ChannelHandler remove(String name)

      Removes the `ChannelHandler` with the specified name from this pipeline.
      Returns:
        the removed handler
      Throws:
        `NoSuchElementException` - if there's no such handler with the specified name in this pipeline
        `NullPointerException` - if the specified name is `null`

    - #### remove

          <T extends ChannelHandler> T remove(Class<T> handlerType)

      Removes the `ChannelHandler` of the specified type from this pipeline
      Type Parameters:
        `T` - the type of the handler
      Parameters:
        `handlerType` - the type of the handler
      Returns:
        the removed handler
      Throws:
        `NoSuchElementException` - if there's no such handler of the specified type in this pipeline
        `NullPointerException` - if the specified handler type is `null`

    - #### removeFirst

          ChannelHandler removeFirst()

      Removes the first `ChannelHandler` in this pipeline.
      Returns:
        the removed handler
      Throws:
        `NoSuchElementException` - if this pipeline is empty

    - #### removeLast

          ChannelHandler removeLast()

      Removes the last `ChannelHandler` in this pipeline.
      Returns:
        the removed handler
      Throws:
        `NoSuchElementException` - if this pipeline is empty

    - #### replace

          void replace(ChannelHandler oldHandler,
                     String newName,
                     ChannelHandler newHandler)

      Replaces the specified `ChannelHandler` with a new handler in this pipeline.
      Throws:
        `NoSuchElementException` - if the specified old handler does not exist in this pipeline
        `IllegalArgumentException` - if a handler with the specified new name already exists in this pipeline, except for the handler to be replaced
        `NullPointerException` - if the specified old handler, new name, or new handler is `null`

    - #### replace

          ChannelHandler replace(String oldName,
                               String newName,
                               ChannelHandler newHandler)

      Replaces the `ChannelHandler` of the specified name with a new handler in this pipeline.
      Returns:
        the removed handler
      Throws:
        `NoSuchElementException` - if the handler with the specified old name does not exist in this pipeline
        `IllegalArgumentException` - if a handler with the specified new name already exists in this pipeline, except for the handler to be replaced
        `NullPointerException` - if the specified old handler, new name, or new handler is `null`

    - #### replace

          <T extends ChannelHandler> T replace(Class<T> oldHandlerType,
                                             String newName,
                                             ChannelHandler newHandler)

      Replaces the `ChannelHandler` of the specified type with a new handler in this pipeline.
      Returns:
        the removed handler
      Throws:
        `NoSuchElementException` - if the handler of the specified old handler type does not exist in this pipeline
        `IllegalArgumentException` - if a handler with the specified new name already exists in this pipeline, except for the handler to be replaced
        `NullPointerException` - if the specified old handler, new name, or new handler is `null`

    - #### getFirst

          ChannelHandler getFirst()

      Returns the first `ChannelHandler` in this pipeline.
      Returns:
        the first handler. `null` if this pipeline is empty.

    - #### getLast

          ChannelHandler getLast()

      Returns the last `ChannelHandler` in this pipeline.
      Returns:
        the last handler. `null` if this pipeline is empty.

    - #### get

          ChannelHandler get(String name)

      Returns the `ChannelHandler` with the specified name in this pipeline.
      Returns:
        the handler with the specified name. `null` if there's no such handler in this pipeline.

    - #### get

          <T extends ChannelHandler> T get(Class<T> handlerType)

      Returns the `ChannelHandler` of the specified type in this pipeline.
      Returns:
        the handler of the specified handler type. `null` if there's no such handler in this pipeline.

    - #### getContext

          ChannelHandlerContext getContext(ChannelHandler handler)

      Returns the context object of the specified `ChannelHandler` in this pipeline.
      Returns:
        the context object of the specified handler. `null` if there's no such handler in this pipeline.

    - #### getContext

          ChannelHandlerContext getContext(String name)

      Returns the context object of the `ChannelHandler` with the specified name in this pipeline.
      Returns:
        the context object of the handler with the specified name. `null` if there's no such handler in this pipeline.

    - #### getContext

          ChannelHandlerContext getContext(Class<? extends ChannelHandler> handlerType)

      Returns the context object of the `ChannelHandler` of the specified type in this pipeline.
      Returns:
        the context object of the handler of the specified type. `null` if there's no such handler in this pipeline.

    - #### sendUpstream

          void sendUpstream(ChannelEvent e)

      Sends the specified `ChannelEvent` to the first `ChannelUpstreamHandler` in this pipeline.
      Throws:
        `NullPointerException` - if the specified event is `null`

    - #### sendDownstream

          void sendDownstream(ChannelEvent e)

      Sends the specified `ChannelEvent` to the last `ChannelDownstreamHandler` in this pipeline.
      Throws:
        `NullPointerException` - if the specified event is `null`

    - #### execute

          ChannelFuture execute(Runnable task)

      Schedules the specified task to be executed in the I/O thread associated with this pipeline's `Channel`.

    - #### getChannel

          Channel getChannel()

      Returns the `Channel` that this pipeline is attached to.
      Returns:
        the channel. `null` if this pipeline is not attached yet.

    - #### getSink

          ChannelSink getSink()

      Returns the `ChannelSink` that this pipeline is attached to.
      Returns:
        the sink. `null` if this pipeline is not attached yet.

    - #### attach

          void attach(Channel channel,
                    ChannelSink sink)

      Attaches this pipeline to the specified `Channel` and `ChannelSink`. Once a pipeline is attached, it can't be detached nor attached again.
      Throws:
        `IllegalStateException` - if this pipeline is attached already

    - #### isAttached

          boolean isAttached()

      Returns `true` if and only if this pipeline is attached to a `Channel`.

    - #### getNames

          List<String> getNames()

      Returns the `List` of the handler names.

    - #### toMap

          Map<String,ChannelHandler> toMap()

      Converts this pipeline into an ordered `Map` whose keys are handler names and whose values are handlers.

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