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
`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.