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 }