View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the License. You may obtain a copy of the License at:
    7    *
    8    *   http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  package org.jboss.netty.channel;
    17
    18  import java.io.InputStream;
    19  import java.io.OutputStream;
    20  import java.util.List;
    21  import java.util.Map;
    22  import java.util.NoSuchElementException;
    23
    24  import org.jboss.netty.buffer.ChannelBuffer;
    25  import org.jboss.netty.handler.execution.ExecutionHandler;
    26  import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
    27  import org.jboss.netty.handler.ssl.SslHandler;
    28
    29
    30  /**
    31   * A list of {@link ChannelHandler}s which handles or intercepts
    32   * {@link ChannelEvent}s of a {@link Channel}.  {@link ChannelPipeline}
    33   * implements an advanced form of the
    34   * <a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/InterceptingFilter.html">Intercepting
    35   * Filter</a> pattern to give a user full control over how an event is handled
    36   * and how the {@link ChannelHandler}s in the pipeline interact with each other.
    37   *
    38   * <h3>Creation of a pipeline</h3>
    39   *
    40   * For each new channel, a new pipeline must be created and attached to the
    41   * channel.  Once attached, the coupling between the channel and the pipeline
    42   * is permanent; the channel cannot attach another pipeline to it nor detach
    43   * the current pipeline from it.
    44   * <p>
    45   * The recommended way to create a new pipeline is to use the helper methods in
    46   * {@link Channels} rather than calling an individual implementation's
    47   * constructor:
    48   * <pre>
    49   * import static org.jboss.netty.channel.{@link Channels}.*;
    50   * {@link ChannelPipeline} pipeline = pipeline(); // same with Channels.pipeline()
    51   * </pre>
    52   *
    53   * <h3>How an event flows in a pipeline</h3>
    54   *
    55   * The following diagram describes how {@link ChannelEvent}s are processed by
    56   * {@link ChannelHandler}s in a {@link ChannelPipeline} typically.
    57   * A {@link ChannelEvent} can be handled by either a {@link ChannelUpstreamHandler}
    58   * or a {@link ChannelDownstreamHandler} and be forwarded to the closest
    59   * handler by calling {@link ChannelHandlerContext#sendUpstream(ChannelEvent)}
    60   * or {@link ChannelHandlerContext#sendDownstream(ChannelEvent)}.  The meaning
    61   * of the event is interpreted somewhat differently depending on whether it is
    62   * going upstream or going downstream. Please refer to {@link ChannelEvent} for
    63   * more information.
    64   * <pre>
    65   *                                       I/O Request
    66   *                                     via {@link Channel} or
    67   *                                 {@link ChannelHandlerContext}
    68   *                                           |
    69   *  +----------------------------------------+---------------+
    70   *  |                  ChannelPipeline       |               |
    71   *  |                                       \|/              |
    72   *  |  +----------------------+  +-----------+------------+  |
    73   *  |  | Upstream Handler  N  |  | Downstream Handler  1  |  |
    74   *  |  +----------+-----------+  +-----------+------------+  |
    75   *  |            /|\                         |               |
    76   *  |             |                         \|/              |
    77   *  |  +----------+-----------+  +-----------+------------+  |
    78   *  |  | Upstream Handler N-1 |  | Downstream Handler  2  |  |
    79   *  |  +----------+-----------+  +-----------+------------+  |
    80   *  |            /|\                         .               |
    81   *  |             .                          .               |
    82   *  |     [ sendUpstream() ]        [ sendDownstream() ]     |
    83   *  |     [ + INBOUND data ]        [ + OUTBOUND data  ]     |
    84   *  |             .                          .               |
    85   *  |             .                         \|/              |
    86   *  |  +----------+-----------+  +-----------+------------+  |
    87   *  |  | Upstream Handler  2  |  | Downstream Handler M-1 |  |
    88   *  |  +----------+-----------+  +-----------+------------+  |
    89   *  |            /|\                         |               |
    90   *  |             |                         \|/              |
    91   *  |  +----------+-----------+  +-----------+------------+  |
    92   *  |  | Upstream Handler  1  |  | Downstream Handler  M  |  |
    93   *  |  +----------+-----------+  +-----------+------------+  |
    94   *  |            /|\                         |               |
    95   *  +-------------+--------------------------+---------------+
    96   *                |                         \|/
    97   *  +-------------+--------------------------+---------------+
    98   *  |             |                          |               |
    99   *  |     [ Socket.read() ]          [ Socket.write() ]      |
    100  *  |                                                        |
    101  *  |  Netty Internal I/O Threads (Transport Implementation) |
    102  *  +--------------------------------------------------------+
    103  * </pre>
    104  * An upstream event is handled by the upstream handlers in the bottom-up
    105  * direction as shown on the left side of the diagram.  An upstream handler
    106  * usually handles the inbound data generated by the I/O thread on the bottom
    107  * of the diagram.  The inbound data is often read from a remote peer via the
    108  * actual input operation such as {@link InputStream#read(byte[])}.
    109  * If an upstream event goes beyond the top upstream handler, it is discarded
    110  * silently.
    111  * <p>
    112  * A downstream event is handled by the downstream handler in the top-down
    113  * direction as shown on the right side of the diagram.  A downstream handler
    114  * usually generates or transforms the outbound traffic such as write requests.
    115  * If a downstream event goes beyond the bottom downstream handler, it is
    116  * handled by an I/O thread associated with the {@link Channel}. The I/O thread
    117  * often performs the actual output operation such as {@link OutputStream#write(byte[])}.
    118  * <p>
    119  * For example, let us assume that we created the following pipeline:
    120  * <pre>
    121  * {@link ChannelPipeline} p = {@link Channels}.pipeline();
    122  * p.addLast("1", new UpstreamHandlerA());
    123  * p.addLast("2", new UpstreamHandlerB());
    124  * p.addLast("3", new DownstreamHandlerA());
    125  * p.addLast("4", new DownstreamHandlerB());
    126  * p.addLast("5", new UpstreamHandlerX());
    127  * </pre>
    128  * In the example above, the class whose name starts with {@code Upstream} means
    129  * it is an upstream handler.  The class whose name starts with
    130  * {@code Downstream} means it is a downstream handler.
    131  * <p>
    132  * In the given example configuration, the handler evaluation order is 1, 2, 3,
    133  * 4, 5 when an event goes upstream.  When an event goes downstream, the order
    134  * is 5, 4, 3, 2, 1.  On top of this principle, {@link ChannelPipeline} skips
    135  * the evaluation of certain handlers to shorten the stack depth:
    136  * <ul>
    137  * <li>3 and 4 don't implement {@link ChannelUpstreamHandler}, and therefore the
    138  *     actual evaluation order of an upstream event will be: 1, 2, and 5.</li>
    139  * <li>1, 2, and 5 don't implement {@link ChannelDownstreamHandler}, and
    140  *     therefore the actual evaluation order of a downstream event will be:
    141  *     4 and 3.</li>
    142  * <li>If 5 extended {@link SimpleChannelHandler} which implements both
    143  *     {@link ChannelUpstreamHandler} and {@link ChannelDownstreamHandler}, the
    144  *     evaluation order of an upstream and a downstream event could be 125 and
    145  *     543 respectively.</li>
    146  * </ul>
    147  *
    148  * <h3>Building a pipeline</h3>
    149  * <p>
    150  * A user is supposed to have one or more {@link ChannelHandler}s in a
    151  * pipeline to receive I/O events (e.g. read) and to request I/O operations
    152  * (e.g. write and close).  For example, a typical server will have the following
    153  * handlers in each channel's pipeline, but your mileage may vary depending on
    154  * the complexity and characteristics of the protocol and business logic:
    155  *
    156  * <ol>
    157  * <li>Protocol Decoder - translates binary data (e.g. {@link ChannelBuffer})
    158  *                        into a Java object.</li>
    159  * <li>Protocol Encoder - translates a Java object into binary data.</li>
    160  * <li>{@link ExecutionHandler} - applies a thread model.</li>
    161  * <li>Business Logic Handler - performs the actual business logic
    162  *                              (e.g. database access).</li>
    163  * </ol>
    164  *
    165  * and it could be represented as shown in the following example:
    166  *
    167  * <pre>
    168  * {@link ChannelPipeline} pipeline = {@link Channels#pipeline() Channels.pipeline()};
    169  * pipeline.addLast("decoder", new MyProtocolDecoder());
    170  * pipeline.addLast("encoder", new MyProtocolEncoder());
    171  * pipeline.addLast("executor", new {@link ExecutionHandler}(
    172  *         new {@link OrderedMemoryAwareThreadPoolExecutor}(16, 1048576, 1048576)));
    173  * pipeline.addLast("handler", new MyBusinessLogicHandler());
    174  * </pre>
    175  *
    176  * <h3>Thread safety</h3>
    177  * <p>
    178  * A {@link ChannelHandler} can be added or removed at any time because a
    179  * {@link ChannelPipeline} is thread safe.  For example, you can insert a
    180  * {@link SslHandler} when sensitive information is about to be exchanged,
    181  * and remove it after the exchange.
    182  *
    183  * <h3>Pitfall</h3>
    184  * <p>
    185  * Due to the internal implementation detail of the current default
    186  * {@link ChannelPipeline}, the following code does not work as expected if
    187  * <tt>FirstHandler</tt> is the last handler in the pipeline:
    188  * <pre>
    189  * public class FirstHandler extends {@link SimpleChannelUpstreamHandler} {
    190  *
    191  *     {@code @Override}
    192  *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
    193  *         // Remove this handler from the pipeline,
    194  *         ctx.getPipeline().remove(this);
    195  *         // And let SecondHandler handle the current event.
    196  *         ctx.getPipeline().addLast("2nd", new SecondHandler());
    197  *         ctx.sendUpstream(e);
    198  *     }
    199  * }
    200  * </pre>
    201  * To implement the expected behavior, you have to add <tt>SecondHandler</tt>
    202  * before the removal or make sure there is at least one more handler between
    203  * <tt>FirstHandler</tt> and <tt>SecondHandler</tt>.
    204  *
    205  * @apiviz.landmark
    206  * @apiviz.composedOf org.jboss.netty.channel.ChannelHandlerContext
    207  * @apiviz.owns       org.jboss.netty.channel.ChannelHandler
    208  * @apiviz.uses       org.jboss.netty.channel.ChannelSink - - sends events downstream
    209  */
    210 public interface ChannelPipeline {
    211
    212     /**
    213      * Inserts a {@link ChannelHandler} at the first position of this pipeline.
    214      *
    215      * @param name     the name of the handler to insert first
    216      * @param handler  the handler to insert first
    217      *
    218      * @throws IllegalArgumentException
    219      *         if there's an entry with the same name already in the pipeline
    220      * @throws NullPointerException
    221      *         if the specified name or handler is {@code null}
    222      */
    223     void addFirst(String name, ChannelHandler handler);
    224
    225     /**
    226      * Appends a {@link ChannelHandler} at the last position of this pipeline.
    227      *
    228      * @param name     the name of the handler to append
    229      * @param handler  the handler to append
    230      *
    231      * @throws IllegalArgumentException
    232      *         if there's an entry with the same name already in the pipeline
    233      * @throws NullPointerException
    234      *         if the specified name or handler is {@code null}
    235      */
    236     void addLast(String name, ChannelHandler handler);
    237
    238     /**
    239      * Inserts a {@link ChannelHandler} before an existing handler of this
    240      * pipeline.
    241      *
    242      * @param baseName  the name of the existing handler
    243      * @param name      the name of the handler to insert before
    244      * @param handler   the handler to insert before
    245      *
    246      * @throws NoSuchElementException
    247      *         if there's no such entry with the specified {@code baseName}
    248      * @throws IllegalArgumentException
    249      *         if there's an entry with the same name already in the pipeline
    250      * @throws NullPointerException
    251      *         if the specified baseName, name, or handler is {@code null}
    252      */
    253     void addBefore(String baseName, String name, ChannelHandler handler);
    254
    255     /**
    256      * Inserts a {@link ChannelHandler} after an existing handler of this
    257      * pipeline.
    258      *
    259      * @param baseName  the name of the existing handler
    260      * @param name      the name of the handler to insert after
    261      * @param handler   the handler to insert after
    262      *
    263      * @throws NoSuchElementException
    264      *         if there's no such entry with the specified {@code baseName}
    265      * @throws IllegalArgumentException
    266      *         if there's an entry with the same name already in the pipeline
    267      * @throws NullPointerException
    268      *         if the specified baseName, name, or handler is {@code null}
    269      */
    270     void addAfter(String baseName, String name, ChannelHandler handler);
    271
    272     /**
    273      * Removes the specified {@link ChannelHandler} from this pipeline.
    274      *
    275      * @throws NoSuchElementException
    276      *         if there's no such handler in this pipeline
    277      * @throws NullPointerException
    278      *         if the specified handler is {@code null}
    279      */
    280     void remove(ChannelHandler handler);
    281
    282     /**
    283      * Removes the {@link ChannelHandler} with the specified name from this
    284      * pipeline.
    285      *
    286      * @return the removed handler
    287      *
    288      * @throws NoSuchElementException
    289      *         if there's no such handler with the specified name in this pipeline
    290      * @throws NullPointerException
    291      *         if the specified name is {@code null}
    292      */
    293     ChannelHandler remove(String name);
    294
    295     /**
    296      * Removes the {@link ChannelHandler} of the specified type from this
    297      * pipeline
    298      *
    299      * @param <T>          the type of the handler
    300      * @param handlerType  the type of the handler
    301      *
    302      * @return the removed handler
    303      *
    304      * @throws NoSuchElementException
    305      *         if there's no such handler of the specified type in this pipeline
    306      * @throws NullPointerException
    307      *         if the specified handler type is {@code null}
    308      */
    309     <T extends ChannelHandler> T remove(Class<T> handlerType);
    310
    311     /**
    312      * Removes the first {@link ChannelHandler} in this pipeline.
    313      *
    314      * @return the removed handler
    315      *
    316      * @throws NoSuchElementException
    317      *         if this pipeline is empty
    318      */
    319     ChannelHandler removeFirst();
    320
    321     /**
    322      * Removes the last {@link ChannelHandler} in this pipeline.
    323      *
    324      * @return the removed handler
    325      *
    326      * @throws NoSuchElementException
    327      *         if this pipeline is empty
    328      */
    329     ChannelHandler removeLast();
    330
    331     /**
    332      * Replaces the specified {@link ChannelHandler} with a new handler in
    333      * this pipeline.
    334      *
    335      * @throws NoSuchElementException
    336      *         if the specified old handler does not exist in this pipeline
    337      * @throws IllegalArgumentException
    338      *         if a handler with the specified new name already exists in this
    339      *         pipeline, except for the handler to be replaced
    340      * @throws NullPointerException
    341      *         if the specified old handler, new name, or new handler is
    342      *         {@code null}
    343      */
    344     void replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);
    345
    346     /**
    347      * Replaces the {@link ChannelHandler} of the specified name with a new
    348      * handler in this pipeline.
    349      *
    350      * @return the removed handler
    351      *
    352      * @throws NoSuchElementException
    353      *         if the handler with the specified old name does not exist in this pipeline
    354      * @throws IllegalArgumentException
    355      *         if a handler with the specified new name already exists in this
    356      *         pipeline, except for the handler to be replaced
    357      * @throws NullPointerException
    358      *         if the specified old handler, new name, or new handler is
    359      *         {@code null}
    360      */
    361     ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);
    362
    363     /**
    364      * Replaces the {@link ChannelHandler} of the specified type with a new
    365      * handler in this pipeline.
    366      *
    367      * @return the removed handler
    368      *
    369      * @throws NoSuchElementException
    370      *         if the handler of the specified old handler type does not exist
    371      *         in this pipeline
    372      * @throws IllegalArgumentException
    373      *         if a handler with the specified new name already exists in this
    374      *         pipeline, except for the handler to be replaced
    375      * @throws NullPointerException
    376      *         if the specified old handler, new name, or new handler is
    377      *         {@code null}
    378      */
    379     <T extends ChannelHandler> T replace(Class<T> oldHandlerType, String newName, ChannelHandler newHandler);
    380
    381     /**
    382      * Returns the first {@link ChannelHandler} in this pipeline.
    383      *
    384      * @return the first handler.  {@code null} if this pipeline is empty.
    385      */
    386     ChannelHandler getFirst();
    387
    388     /**
    389      * Returns the last {@link ChannelHandler} in this pipeline.
    390      *
    391      * @return the last handler.  {@code null} if this pipeline is empty.
    392      */
    393     ChannelHandler getLast();
    394
    395     /**
    396      * Returns the {@link ChannelHandler} with the specified name in this
    397      * pipeline.
    398      *
    399      * @return the handler with the specified name.
    400      *         {@code null} if there's no such handler in this pipeline.
    401      */
    402     ChannelHandler get(String name);
    403
    404     /**
    405      * Returns the {@link ChannelHandler} of the specified type in this
    406      * pipeline.
    407      *
    408      * @return the handler of the specified handler type.
    409      *         {@code null} if there's no such handler in this pipeline.
    410      */
    411     <T extends ChannelHandler> T get(Class<T> handlerType);
    412
    413     /**
    414      * Returns the context object of the specified {@link ChannelHandler} in
    415      * this pipeline.
    416      *
    417      * @return the context object of the specified handler.
    418      *         {@code null} if there's no such handler in this pipeline.
    419      */
    420     ChannelHandlerContext getContext(ChannelHandler handler);
    421
    422     /**
    423      * Returns the context object of the {@link ChannelHandler} with the
    424      * specified name in this pipeline.
    425      *
    426      * @return the context object of the handler with the specified name.
    427      *         {@code null} if there's no such handler in this pipeline.
    428      */
    429     ChannelHandlerContext getContext(String name);
    430
    431     /**
    432      * Returns the context object of the {@link ChannelHandler} of the
    433      * specified type in this pipeline.
    434      *
    435      * @return the context object of the handler of the specified type.
    436      *         {@code null} if there's no such handler in this pipeline.
    437      */
    438     ChannelHandlerContext getContext(Class<? extends ChannelHandler> handlerType);
    439
    440
    441     /**
    442      * Sends the specified {@link ChannelEvent} to the first
    443      * {@link ChannelUpstreamHandler} in this pipeline.
    444      *
    445      * @throws NullPointerException
    446      *         if the specified event is {@code null}
    447      */
    448     void sendUpstream(ChannelEvent e);
    449
    450     /**
    451      * Sends the specified {@link ChannelEvent} to the last
    452      * {@link ChannelDownstreamHandler} in this pipeline.
    453      *
    454      * @throws NullPointerException
    455      *         if the specified event is {@code null}
    456      */
    457     void sendDownstream(ChannelEvent e);
    458
    459     /**
    460      * Schedules the specified task to be executed in the I/O thread associated
    461      * with this pipeline's {@link Channel}.
    462      */
    463     ChannelFuture execute(Runnable task);
    464
    465     /**
    466      * Returns the {@link Channel} that this pipeline is attached to.
    467      *
    468      * @return the channel. {@code null} if this pipeline is not attached yet.
    469      */
    470     Channel getChannel();
    471
    472     /**
    473      * Returns the {@link ChannelSink} that this pipeline is attached to.
    474      *
    475      * @return the sink. {@code null} if this pipeline is not attached yet.
    476      */
    477     ChannelSink getSink();
    478
    479     /**
    480      * Attaches this pipeline to the specified {@link Channel} and
    481      * {@link ChannelSink}.  Once a pipeline is attached, it can't be detached
    482      * nor attached again.
    483      *
    484      * @throws IllegalStateException if this pipeline is attached already
    485      */
    486     void attach(Channel channel, ChannelSink sink);
    487
    488     /**
    489      * Returns {@code true} if and only if this pipeline is attached to
    490      * a {@link Channel}.
    491      */
    492     boolean isAttached();
    493
    494     /**
    495      * Returns the {@link List} of the handler names.
    496      */
    497     List<String> getNames();
    498
    499     /**
    500      * Converts this pipeline into an ordered {@link Map} whose keys are
    501      * handler names and whose values are handlers.
    502      */
    503     Map<String, ChannelHandler> toMap();
    504 }