View Javadoc

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