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.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}(new {@link OrderedMemoryAwareThreadPoolExecutor}(16, 1048576, 1048576)));
172  * pipeline.addLast("handler", new MyBusinessLogicHandler());
173  * </pre>
174  *
175  * <h3>Thread safety</h3>
176  * <p>
177  * A {@link ChannelHandler} can be added or removed at any time because a
178  * {@link ChannelPipeline} is thread safe.  For example, you can insert a
179  * {@link SslHandler} when sensitive information is about to be exchanged,
180  * and remove it after the exchange.
181  *
182  * <h3>Pitfall</h3>
183  * <p>
184  * Due to the internal implementation detail of the current default
185  * {@link ChannelPipeline}, the following code does not work as expected if
186  * <tt>FirstHandler</tt> is the last handler in the pipeline:
187  * <pre>
188  * public class FirstHandler extends {@link SimpleChannelUpstreamHandler} {
189  *
190  *     {@code @Override}
191  *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
192  *         // Remove this handler from the pipeline,
193  *         ctx.getPipeline().remove(this);
194  *         // And let SecondHandler handle the current event.
195  *         ctx.getPipeline().addLast("2nd", new SecondHandler());
196  *         ctx.sendUpstream(e);
197  *     }
198  * }
199  * </pre>
200  * To implement the expected behavior, you have to add <tt>SecondHandler</tt>
201  * before the removal or make sure there is at least one more handler between
202  * <tt>FirstHandler</tt> and <tt>SecondHandler</tt>.
203  *
204  * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
205  * @author <a href="http://gleamynode.net/">Trustin Lee</a>
206  *
207  * @version $Rev: 2153 $, $Date: 2010-02-17 17:24:25 +0900 (Wed, 17 Feb 2010) $
208  *
209  * @apiviz.landmark
210  * @apiviz.composedOf org.jboss.netty.channel.ChannelHandlerContext
211  * @apiviz.owns       org.jboss.netty.channel.ChannelHandler
212  * @apiviz.uses       org.jboss.netty.channel.ChannelSink - - sends events downstream
213  */
214 public interface ChannelPipeline {
215 
216     /**
217      * Inserts a {@link ChannelHandler} at the first position of this pipeline.
218      *
219      * @param name     the name of the handler to insert first
220      * @param handler  the handler to insert first
221      *
222      * @throws IllegalArgumentException
223      *         if there's an entry with the same name already in the pipeline
224      * @throws NullPointerException
225      *         if the specified name or handler is {@code null}
226      */
227     void addFirst (String name, ChannelHandler handler);
228 
229     /**
230      * Appends a {@link ChannelHandler} at the last position of this pipeline.
231      *
232      * @param name     the name of the handler to append
233      * @param handler  the handler to append
234      *
235      * @throws IllegalArgumentException
236      *         if there's an entry with the same name already in the pipeline
237      * @throws NullPointerException
238      *         if the specified name or handler is {@code null}
239      */
240     void addLast  (String name, ChannelHandler handler);
241 
242     /**
243      * Inserts a {@link ChannelHandler} before an existing handler of this
244      * pipeline.
245      *
246      * @param baseName  the name of the existing handler
247      * @param name      the name of the handler to insert before
248      * @param handler   the handler to insert before
249      *
250      * @throws NoSuchElementException
251      *         if there's no such entry with the specified {@code baseName}
252      * @throws IllegalArgumentException
253      *         if there's an entry with the same name already in the pipeline
254      * @throws NullPointerException
255      *         if the specified baseName, name, or handler is {@code null}
256      */
257     void addBefore(String baseName, String name, ChannelHandler handler);
258 
259     /**
260      * Inserts a {@link ChannelHandler} after an existing handler of this
261      * pipeline.
262      *
263      * @param baseName  the name of the existing handler
264      * @param name      the name of the handler to insert after
265      * @param handler   the handler to insert after
266      *
267      * @throws NoSuchElementException
268      *         if there's no such entry with the specified {@code baseName}
269      * @throws IllegalArgumentException
270      *         if there's an entry with the same name already in the pipeline
271      * @throws NullPointerException
272      *         if the specified baseName, name, or handler is {@code null}
273      */
274     void addAfter (String baseName, String name, ChannelHandler handler);
275 
276     /**
277      * Removes the specified {@link ChannelHandler} from this pipeline.
278      *
279      * @throws NoSuchElementException
280      *         if there's no such handler in this pipeline
281      * @throws NullPointerException
282      *         if the specified handler is {@code null}
283      */
284     void remove(ChannelHandler handler);
285 
286     /**
287      * Removes the {@link ChannelHandler} with the specified name from this
288      * pipeline.
289      *
290      * @return the removed handler
291      *
292      * @throws NoSuchElementException
293      *         if there's no such handler with the specified name in this pipeline
294      * @throws NullPointerException
295      *         if the specified name is {@code null}
296      */
297     ChannelHandler remove(String name);
298 
299     /**
300      * Removes the {@link ChannelHandler} of the specified type from this
301      * pipeline
302      *
303      * @param <T>          the type of the handler
304      * @param handlerType  the type of the handler
305      *
306      * @return the removed handler
307      *
308      * @throws NoSuchElementException
309      *         if there's no such handler of the specified type in this pipeline
310      * @throws NullPointerException
311      *         if the specified handler type is {@code null}
312      */
313     <T extends ChannelHandler> T remove(Class<T> handlerType);
314 
315     /**
316      * Removes the first {@link ChannelHandler} in this pipeline.
317      *
318      * @return the removed handler
319      *
320      * @throws NoSuchElementException
321      *         if this pipeline is empty
322      */
323     ChannelHandler removeFirst();
324 
325     /**
326      * Removes the last {@link ChannelHandler} in this pipeline.
327      *
328      * @return the removed handler
329      *
330      * @throws NoSuchElementException
331      *         if this pipeline is empty
332      */
333     ChannelHandler removeLast();
334 
335     /**
336      * Replaces the specified {@link ChannelHandler} with a new handler in
337      * this pipeline.
338      *
339      * @throws NoSuchElementException
340      *         if the specified old handler does not exist in this pipeline
341      * @throws IllegalArgumentException
342      *         if a handler with the specified new name already exists in this
343      *         pipeline, except for the handler to be replaced
344      * @throws NullPointerException
345      *         if the specified old handler, new name, or new handler is
346      *         {@code null}
347      */
348     void replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);
349 
350     /**
351      * Replaces the {@link ChannelHandler} of the specified name with a new
352      * handler in this pipeline.
353      *
354      * @return the removed handler
355      *
356      * @throws NoSuchElementException
357      *         if the handler with the specified old name does not exist in this pipeline
358      * @throws IllegalArgumentException
359      *         if a handler with the specified new name already exists in this
360      *         pipeline, except for the handler to be replaced
361      * @throws NullPointerException
362      *         if the specified old handler, new name, or new handler is
363      *         {@code null}
364      */
365     ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);
366 
367     /**
368      * Replaces the {@link ChannelHandler} of the specified type with a new
369      * handler in this pipeline.
370      *
371      * @return the removed handler
372      *
373      * @throws NoSuchElementException
374      *         if the handler of the specified old handler type does not exist
375      *         in this pipeline
376      * @throws IllegalArgumentException
377      *         if a handler with the specified new name already exists in this
378      *         pipeline, except for the handler to be replaced
379      * @throws NullPointerException
380      *         if the specified old handler, new name, or new handler is
381      *         {@code null}
382      */
383     <T extends ChannelHandler> T replace(Class<T> oldHandlerType, String newName, ChannelHandler newHandler);
384 
385     /**
386      * Returns the first {@link ChannelHandler} in this pipeline.
387      *
388      * @return the first handler.  {@code null} if this pipeline is empty.
389      */
390     ChannelHandler getFirst();
391 
392     /**
393      * Returns the last {@link ChannelHandler} in this pipeline.
394      *
395      * @return the last handler.  {@code null} if this pipeline is empty.
396      */
397     ChannelHandler getLast();
398 
399     /**
400      * Returns the {@link ChannelHandler} with the specified name in this
401      * pipeline.
402      *
403      * @return the handler with the specified name.
404      *         {@code null} if there's no such handler in this pipeline.
405      */
406     ChannelHandler get(String name);
407 
408     /**
409      * Returns the {@link ChannelHandler} of the specified type in this
410      * pipeline.
411      *
412      * @return the handler of the specified handler type.
413      *         {@code null} if there's no such handler in this pipeline.
414      */
415     <T extends ChannelHandler> T get(Class<T> handlerType);
416 
417     /**
418      * Returns the context object of the specified {@link ChannelHandler} in
419      * this pipeline.
420      *
421      * @return the context object of the specified handler.
422      *         {@code null} if there's no such handler in this pipeline.
423      */
424     ChannelHandlerContext getContext(ChannelHandler handler);
425 
426     /**
427      * Returns the context object of the {@link ChannelHandler} with the
428      * specified name in this pipeline.
429      *
430      * @return the context object of the handler with the specified name.
431      *         {@code null} if there's no such handler in this pipeline.
432      */
433     ChannelHandlerContext getContext(String name);
434 
435     /**
436      * Returns the context object of the {@link ChannelHandler} of the
437      * specified type in this pipeline.
438      *
439      * @return the context object of the handler of the specified type.
440      *         {@code null} if there's no such handler in this pipeline.
441      */
442     ChannelHandlerContext getContext(Class<? extends ChannelHandler> handlerType);
443 
444 
445     /**
446      * Sends the specified {@link ChannelEvent} to the first
447      * {@link ChannelUpstreamHandler} in this pipeline.
448      *
449      * @throws NullPointerException
450      *         if the specified event is {@code null}
451      */
452     void sendUpstream(ChannelEvent e);
453 
454     /**
455      * Sends the specified {@link ChannelEvent} to the last
456      * {@link ChannelDownstreamHandler} in this pipeline.
457      *
458      * @throws NullPointerException
459      *         if the specified event is {@code null}
460      */
461     void sendDownstream(ChannelEvent e);
462 
463     /**
464      * Returns the {@link Channel} that this pipeline is attached to.
465      *
466      * @return the channel. {@code null} if this pipeline is not attached yet.
467      */
468     Channel getChannel();
469 
470     /**
471      * Returns the {@link ChannelSink} that this pipeline is attached to.
472      *
473      * @return the sink. {@code null} if this pipeline is not attached yet.
474      */
475     ChannelSink getSink();
476 
477     /**
478      * Attaches this pipeline to the specified {@link Channel} and
479      * {@link ChannelSink}.  Once a pipeline is attached, it can't be detached
480      * nor attached again.
481      *
482      * @throws IllegalStateException if this pipeline is attached already
483      */
484     void attach(Channel channel, ChannelSink sink);
485 
486     /**
487      * Returns {@code true} if and only if this pipeline is attached to
488      * a {@link Channel}.
489      */
490     boolean isAttached();
491 
492     /**
493      * Returns the {@link List} of the handler names.
494      */
495     List<String> getNames();
496 
497     /**
498      * Converts this pipeline into an ordered {@link Map} whose keys are
499      * handler names and whose values are handlers.
500      */
501     Map<String, ChannelHandler> toMap();
502 }