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    *   https://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 io.netty5.channel;
17  
18  import io.netty5.buffer.api.Buffer;
19  
20  import java.net.SocketAddress;
21  import java.nio.ByteBuffer;
22  import java.nio.channels.SocketChannel;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.NoSuchElementException;
27  
28  
29  /**
30   * A list of {@link ChannelHandler}s which handles or intercepts inbound events and outbound operations of a
31   * {@link Channel}. {@link ChannelPipeline} implements an advanced form of the
32   * <a href="https://www.oracle.com/technetwork/java/interceptingfilter-142169.html">Intercepting Filter</a> pattern
33   * to give a user full control over how an event is handled and how the {@link ChannelHandler}s in a pipeline
34   * interact with each other.
35   *
36   * <h3>Creation of a pipeline</h3>
37   *
38   * Each channel has its own pipeline and it is created automatically when a new channel is created.
39   *
40   * <h3>How an event flows in a pipeline</h3>
41   *
42   * The following diagram describes how I/O events are processed by {@link ChannelHandler}s in a {@link ChannelPipeline}
43   * typically. An I/O event is handled by a {@link ChannelHandler} (which may handle inbound or / and outbound events)
44   * and be forwarded to its closest handler by calling the event propagation methods defined in
45   * {@link ChannelHandlerContext}, such as {@link ChannelHandlerContext#fireChannelRead(Object)} and
46   * {@link ChannelHandlerContext#write(Object)}.
47   *
48   * <pre>
49   *                                                 I/O Request
50   *                                            via {@link Channel} or
51   *                                        {@link ChannelHandlerContext}
52   *                                                      |
53   *  +---------------------------------------------------+---------------+
54   *  |                           ChannelPipeline         |               |
55   *  |                                                  \|/              |
56   *  |    +---------------------+            +-----------+----------+    |
57   *  |    | Inbound Handler  N  |            | Outbound Handler  1  |    |
58   *  |    +----------+----------+            +-----------+----------+    |
59   *  |              /|\                                  |               |
60   *  |               |                                  \|/              |
61   *  |    +----------+----------+            +-----------+----------+    |
62   *  |    | Inbound Handler N-1 |            | Outbound Handler  2  |    |
63   *  |    +----------+----------+            +-----------+----------+    |
64   *  |              /|\                                  .               |
65   *  |               .                                   .               |
66   *  | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
67   *  |        [ method call]                       [method call]         |
68   *  |               .                                   .               |
69   *  |               .                                  \|/              |
70   *  |    +----------+----------+            +-----------+----------+    |
71   *  |    | Inbound Handler  2  |            | Outbound Handler M-1 |    |
72   *  |    +----------+----------+            +-----------+----------+    |
73   *  |              /|\                                  |               |
74   *  |               |                                  \|/              |
75   *  |    +----------+----------+            +-----------+----------+    |
76   *  |    | Inbound Handler  1  |            | Outbound Handler  M  |    |
77   *  |    +----------+----------+            +-----------+----------+    |
78   *  |              /|\                                  |               |
79   *  +---------------+-----------------------------------+---------------+
80   *                  |                                  \|/
81   *  +---------------+-----------------------------------+---------------+
82   *  |               |                                   |               |
83   *  |       [ Socket.read() ]                    [ Socket.write() ]     |
84   *  |                                                                   |
85   *  |  Netty Internal I/O Threads (Transport Implementation)            |
86   *  +-------------------------------------------------------------------+
87   * </pre>
88   * An inbound event is handled by the inbound handlers in the bottom-up direction as shown on the left side of the
89   * diagram.  An inbound handler usually handles the inbound data generated by the I/O thread on the bottom of the
90   * diagram.  The inbound data is often read from a remote peer via the actual input operation such as
91   * {@link SocketChannel#read(ByteBuffer)}.  If an inbound event goes beyond the top inbound handler, it is discarded
92   * silently, or logged if it needs your attention.
93   * <p>
94   * An outbound event is handled by the outbound handler in the top-down direction as shown on the right side of the
95   * diagram.  An outbound handler usually generates or transforms the outbound traffic such as write requests.
96   * If an outbound event goes beyond the bottom outbound handler, it is handled by an I/O thread associated with the
97   * {@link Channel}. The I/O thread often performs the actual output operation such as
98   * {@link SocketChannel#write(ByteBuffer)}.
99   * <p>
100  * For example, let us assume that we created the following pipeline:
101  * <pre>
102  * {@link ChannelPipeline} p = ...;
103  * p.addLast("1", new InboundHandlerA());
104  * p.addLast("2", new InboundHandlerB());
105  * p.addLast("3", new OutboundHandlerA());
106  * p.addLast("4", new OutboundHandlerB());
107  * p.addLast("5", new InboundOutboundHandlerX());
108  * </pre>
109  * In the example above, the class whose name starts with {@code Inbound} means it is an inbound handler.
110  * The class whose name starts with {@code Outbound} means it is a outbound handler.
111  * <p>
112  * In the given example configuration, the handler evaluation order is 1, 2, 3, 4, 5 when an event goes inbound.
113  * When an event goes outbound, the order is 5, 4, 3, 2, 1.  On top of this principle, {@link ChannelPipeline} skips
114  * the evaluation of certain handlers to shorten the stack depth:
115  * <ul>
116  * <li>3 and 4 don't implement inbound handling methods of {@link ChannelHandler},
117  *     and therefore the actual evaluation order of an inbound  event will be: 1, 2, and 5.</li>
118  * <li>1 and 2 don't implement outbound handling methods of {@link ChannelHandler}, and therefore the actual evaluation
119  *     order of an outbound event will be: 5, 4, and 3.</li>
120  * <li>If 5 implements both inbound and outbound handling methods of {@link ChannelHandler}, the evaluation order of
121  *     an inbound and a outbound event could be 125 and 543 respectively.</li>
122  * </ul>
123  *
124  * <h3>Forwarding an event to the next handler</h3>
125  *
126  * As you might noticed in the diagram shows, a handler has to invoke the event propagation methods in
127  * {@link ChannelHandlerContext} to forward an event to its next handler.  Those methods include:
128  * <ul>
129  * <li>Inbound event propagation methods:
130  *     <ul>
131  *     <li>{@link ChannelHandlerContext#fireChannelRegistered()}</li>
132  *     <li>{@link ChannelHandlerContext#fireChannelActive()}</li>
133  *     <li>{@link ChannelHandlerContext#fireChannelRead(Object)}</li>
134  *     <li>{@link ChannelHandlerContext#fireChannelReadComplete()}</li>
135  *     <li>{@link ChannelHandlerContext#fireChannelExceptionCaught(Throwable)}</li>
136  *     <li>{@link ChannelHandlerContext#fireChannelInboundEvent(Object)}</li>
137  *     <li>{@link ChannelHandlerContext#fireChannelWritabilityChanged()}</li>
138  *     <li>{@link ChannelHandlerContext#fireChannelInactive()}</li>
139  *     <li>{@link ChannelHandlerContext#fireChannelShutdown(ChannelShutdownDirection)}</li>
140  *     <li>{@link ChannelHandlerContext#fireChannelUnregistered()}</li>
141  *     </ul>
142  * </li>
143  * <li>Outbound event propagation methods:
144  *     <ul>
145  *     <li>{@link ChannelHandlerContext#bind(SocketAddress)}</li>
146  *     <li>{@link ChannelHandlerContext#connect(SocketAddress, SocketAddress)}</li>
147  *     <li>{@link ChannelHandlerContext#write(Object)}</li>
148  *     <li>{@link ChannelHandlerContext#flush()}</li>
149  *     <li>{@link ChannelHandlerContext#read()}</li>
150  *     <li>{@link ChannelHandlerContext#disconnect()}</li>
151  *     <li>{@link ChannelHandlerContext#close()}</li>
152  *     <li>{@link ChannelHandlerContext#shutdown(ChannelShutdownDirection)}</li>
153  *     <li>{@link ChannelHandlerContext#sendOutboundEvent(Object)}</li>
154  *     <li>{@link ChannelHandlerContext#deregister()}</li>
155  *     </ul>
156  * </li>
157  * </ul>
158  *
159  * and the following example shows how the event propagation is usually done:
160  *
161  * <pre>
162  * public class MyInboundHandler implements {@link ChannelHandler} {
163  *     {@code @Override}
164  *     public void channelActive({@link ChannelHandlerContext} ctx) {
165  *         System.out.println("Connected!");
166  *         ctx.fireChannelActive();
167  *     }
168  * }
169  *
170  * public class MyOutboundHandler implements {@link ChannelHandler} {
171  *     {@code @Override}
172  *     public Future&ltVoid&gt close({@link ChannelHandlerContext} ctx) {
173  *         System.out.println("Closing ..");
174  *         return ctx.close();
175  *     }
176  * }
177  * </pre>
178  *
179  * <h3>Building a pipeline</h3>
180  * <p>
181  * A user is supposed to have one or more {@link ChannelHandler}s in a pipeline to receive I/O events (e.g. read) and
182  * to request I/O operations (e.g. write and close). For example, a typical server will have the following handlers
183  * in each channel's pipeline, but your mileage may vary depending on the complexity and characteristics of the
184  * protocol and business logic:
185  *
186  * <ol>
187  * <li>Protocol Decoder - translates binary data (e.g. {@link Buffer}) into a Java object.</li>
188  * <li>Protocol Encoder - translates a Java object into binary data.</li>
189  * <li>Business Logic Handler - performs the actual business logic (e.g. database access).</li>
190  * </ol>
191  *
192  * and it could be represented as shown in the following example:
193  *
194  * <pre>
195  * ...
196  *
197  * {@link ChannelPipeline} pipeline = ch.pipeline();
198  *
199  * pipeline.addLast("decoder", new MyProtocolDecoder());
200  * pipeline.addLast("encoder", new MyProtocolEncoder());
201  *
202  * // If your business logic does block or take a lot of time you should offload the work to an extra
203  * // {@link java.util.concurrent.Executor} to ensure you don't block the {@link EventLoop}.
204  * pipeline.addLast("handler",  new MyBusinessLogicHandler());
205  * </pre>
206  *
207  * <h3>Thread safety</h3>
208  * <p>
209  * A {@link ChannelHandler} can be added or removed at any time because a {@link ChannelPipeline} is thread safe.
210  * For example, you can insert an encryption handler when sensitive information is about to be exchanged, and remove it
211  * after the exchange.
212  */
213 public interface ChannelPipeline
214         extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable<Map.Entry<String, ChannelHandler>> {
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 handler is {@code null}
226      */
227     ChannelPipeline 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 handler is {@code null}
239      */
240     ChannelPipeline 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 or handler is {@code null}
256      */
257     ChannelPipeline 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 or handler is {@code null}
273      */
274     ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);
275 
276     /**
277      * Inserts {@link ChannelHandler}s at the first position of this pipeline. {@code null} handlers will be skipped.
278      *
279      * @param handlers  the handlers to insert first
280      *
281      */
282     ChannelPipeline addFirst(ChannelHandler... handlers);
283 
284     /**
285      * Inserts {@link ChannelHandler}s at the last position of this pipeline. {@code null} handlers will be skipped.
286      *
287      * @param handlers  the handlers to insert last
288      *
289      */
290     ChannelPipeline addLast(ChannelHandler... handlers);
291 
292     /**
293      * Removes the specified {@link ChannelHandler} from this pipeline.
294      *
295      * @param  handler          the {@link ChannelHandler} to remove
296      *
297      * @throws NoSuchElementException
298      *         if there's no such handler in this pipeline
299      * @throws NullPointerException
300      *         if the specified handler is {@code null}
301      */
302     default ChannelPipeline remove(ChannelHandler handler) {
303         if (removeIfExists(handler) == null) {
304             throw new NoSuchElementException();
305         }
306         return this;
307     }
308 
309     /**
310      * Removes the {@link ChannelHandler} with the specified name from this pipeline.
311      *
312      * @param  name             the name under which the {@link ChannelHandler} was stored.
313      *
314      * @return the removed handler
315      *
316      * @throws NoSuchElementException
317      *         if there's no such handler with the specified name in this pipeline
318      * @throws NullPointerException
319      *         if the specified name is {@code null}
320      */
321     default ChannelHandler remove(String name) {
322         ChannelHandler handler = removeIfExists(name);
323         if (handler == null) {
324             throw new NoSuchElementException();
325         }
326         return handler;
327     }
328 
329     /**
330      * Removes the {@link ChannelHandler} of the specified type from this pipeline.
331      *
332      * @param <T>           the type of the handler
333      * @param handlerType   the type of the handler
334      *
335      * @return the removed handler
336      *
337      * @throws NoSuchElementException
338      *         if there's no such handler of the specified type in this pipeline
339      * @throws NullPointerException
340      *         if the specified handler type is {@code null}
341      */
342     default <T extends ChannelHandler> T remove(Class<T> handlerType) {
343         T handler = removeIfExists(handlerType);
344         if (handler == null) {
345             throw new NoSuchElementException();
346         }
347         return handler;
348     }
349 
350     /**
351      * Removes the {@link ChannelHandler} with the specified name from this pipeline if it exists.
352      *
353      * @param  name             the name under which the {@link ChannelHandler} was stored.
354      *
355      * @return the removed handler
356      *
357      * @throws NoSuchElementException
358      *         if there's no such handler with the specified name in this pipeline
359      * @throws NullPointerException
360      *         if the specified name is {@code null}
361      */
362     <T extends ChannelHandler> T removeIfExists(String name);
363 
364     /**
365      * Removes the {@link ChannelHandler} of the specified type from this pipeline if it exists.
366      *
367      * @param <T>           the type of the handler
368      * @param handlerType   the type of the handler
369      *
370      * @return the removed handler or {@code null} if it didn't exist.
371      *
372      * @throws NullPointerException
373      *         if the specified handler type is {@code null}
374      */
375     <T extends ChannelHandler> T removeIfExists(Class<T> handlerType);
376 
377     /**
378      * Removes the specified {@link ChannelHandler} from this pipeline if it exists
379      *
380      * @param  handler          the {@link ChannelHandler} to remove
381      *
382      * @return the removed handler or {@code null} if it didn't exist.
383      *
384      * @throws NullPointerException
385      *         if the specified handler is {@code null}
386      */
387     <T extends ChannelHandler> T removeIfExists(ChannelHandler handler);
388 
389     /**
390      * Removes the first {@link ChannelHandler} in this pipeline.
391      *
392      * @return the removed handler
393      *
394      * @throws NoSuchElementException
395      *         if this pipeline is empty
396      */
397     ChannelHandler removeFirst();
398 
399     /**
400      * Removes the last {@link ChannelHandler} in this pipeline.
401      *
402      * @return the removed handler
403      *
404      * @throws NoSuchElementException
405      *         if this pipeline is empty
406      */
407     ChannelHandler removeLast();
408 
409     /**
410      * Replaces the specified {@link ChannelHandler} with a new handler in this pipeline.
411      *
412      * @param  oldHandler    the {@link ChannelHandler} to be replaced
413      * @param  newName       the name under which the replacement should be added
414      * @param  newHandler    the {@link ChannelHandler} which is used as replacement
415      *
416      * @return itself
417 
418      * @throws NoSuchElementException
419      *         if the specified old handler does not exist in this pipeline
420      * @throws IllegalArgumentException
421      *         if a handler with the specified new name already exists in this
422      *         pipeline, except for the handler to be replaced
423      * @throws NullPointerException
424      *         if the specified old handler or new handler is
425      *         {@code null}
426      */
427     ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);
428 
429     /**
430      * Replaces the {@link ChannelHandler} of the specified name with a new handler in this pipeline.
431      *
432      * @param  oldName       the name of the {@link ChannelHandler} to be replaced
433      * @param  newName       the name under which the replacement should be added
434      * @param  newHandler    the {@link ChannelHandler} which is used as replacement
435      *
436      * @return the removed handler
437      *
438      * @throws NoSuchElementException
439      *         if the handler with the specified old name does not exist in this pipeline
440      * @throws IllegalArgumentException
441      *         if a handler with the specified new name already exists in this
442      *         pipeline, except for the handler to be replaced
443      * @throws NullPointerException
444      *         if the specified old handler or new handler is
445      *         {@code null}
446      */
447     ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);
448 
449     /**
450      * Replaces the {@link ChannelHandler} of the specified type with a new handler in this pipeline.
451      *
452      * @param  oldHandlerType   the type of the handler to be removed
453      * @param  newName          the name under which the replacement should be added
454      * @param  newHandler       the {@link ChannelHandler} which is used as replacement
455      *
456      * @return the removed handler
457      *
458      * @throws NoSuchElementException
459      *         if the handler of the specified old handler type does not exist
460      *         in this pipeline
461      * @throws IllegalArgumentException
462      *         if a handler with the specified new name already exists in this
463      *         pipeline, except for the handler to be replaced
464      * @throws NullPointerException
465      *         if the specified old handler or new handler is
466      *         {@code null}
467      */
468     <T extends ChannelHandler> T replace(Class<T> oldHandlerType, String newName,
469                                          ChannelHandler newHandler);
470 
471     /**
472      * Returns the first {@link ChannelHandler} in this pipeline.
473      *
474      * @return the first handler.  {@code null} if this pipeline is empty.
475      */
476     default ChannelHandler first() {
477         ChannelHandlerContext ctx = firstContext();
478         return ctx == null ? null : ctx.handler();
479     }
480 
481     /**
482      * Returns the context of the first {@link ChannelHandler} in this pipeline.
483      *
484      * @return the context of the first handler.  {@code null} if this pipeline is empty.
485      */
486     ChannelHandlerContext firstContext();
487 
488     /**
489      * Returns the last {@link ChannelHandler} in this pipeline.
490      *
491      * @return the last handler.  {@code null} if this pipeline is empty.
492      */
493     default ChannelHandler last() {
494         ChannelHandlerContext ctx = lastContext();
495         return ctx == null ? null : ctx.handler();
496     }
497 
498     /**
499      * Returns the context of the last {@link ChannelHandler} in this pipeline.
500      *
501      * @return the context of the last handler.  {@code null} if this pipeline is empty.
502      */
503     ChannelHandlerContext lastContext();
504 
505     /**
506      * Returns {@code true} if this {@link ChannelPipeline} is empty, which means no {@link ChannelHandler} is
507      * present.
508      */
509     default boolean isEmpty() {
510         return lastContext() == null;
511     }
512 
513     /**
514      * Returns the {@link ChannelHandler} with the specified name in this
515      * pipeline.
516      *
517      * @return the handler with the specified name.
518      *         {@code null} if there's no such handler in this pipeline.
519      */
520     ChannelHandler get(String name);
521 
522     /**
523      * Returns the {@link ChannelHandler} of the specified type in this
524      * pipeline.
525      *
526      * @return the handler of the specified handler type.
527      *         {@code null} if there's no such handler in this pipeline.
528      */
529     <T extends ChannelHandler> T get(Class<T> handlerType);
530 
531     /**
532      * Returns the context object of the specified {@link ChannelHandler} in
533      * this pipeline.
534      *
535      * @return the context object of the specified handler.
536      *         {@code null} if there's no such handler in this pipeline.
537      */
538     ChannelHandlerContext context(ChannelHandler handler);
539 
540     /**
541      * Returns the context object of the {@link ChannelHandler} with the
542      * specified name in this pipeline.
543      *
544      * @return the context object of the handler with the specified name.
545      *         {@code null} if there's no such handler in this pipeline.
546      */
547     ChannelHandlerContext context(String name);
548 
549     /**
550      * Returns the context object of the {@link ChannelHandler} of the
551      * specified type in this pipeline.
552      *
553      * @return the context object of the handler of the specified type.
554      *         {@code null} if there's no such handler in this pipeline.
555      */
556     ChannelHandlerContext context(Class<? extends ChannelHandler> handlerType);
557 
558     /**
559      * Returns the {@link Channel} that this pipeline is attached to.
560      *
561      * @return the channel. {@code null} if this pipeline is not attached yet.
562      */
563     Channel channel();
564 
565     /**
566      * Returns the {@link List} of the handler names.
567      */
568     default List<String> names() {
569         return new ArrayList<>(toMap().keySet());
570     }
571 
572     /**
573      * Converts this pipeline into an ordered {@link Map} whose keys are
574      * handler names and whose values are handlers.
575      */
576     Map<String, ChannelHandler> toMap();
577 
578     @Override
579     ChannelPipeline fireChannelRegistered();
580 
581     @Override
582     ChannelPipeline fireChannelUnregistered();
583 
584     @Override
585     ChannelPipeline fireChannelActive();
586 
587     @Override
588     ChannelPipeline fireChannelInactive();
589 
590     @Override
591     ChannelPipeline fireChannelShutdown(ChannelShutdownDirection direction);
592 
593     @Override
594     ChannelPipeline fireChannelExceptionCaught(Throwable cause);
595 
596     @Override
597     ChannelPipeline fireChannelInboundEvent(Object event);
598 
599     @Override
600     ChannelPipeline fireChannelRead(Object msg);
601 
602     @Override
603     ChannelPipeline fireChannelReadComplete();
604 
605     @Override
606     ChannelPipeline fireChannelWritabilityChanged();
607 
608     @Override
609     ChannelPipeline flush();
610 
611     /**
612      * The number of the outbound bytes that are buffered / queued in this {@link ChannelPipeline}. This number will
613      * affect the writability of the {@link Channel} together the buffered / queued bytes in the {@link Channel} itself.
614      *
615      * @return the number of buffered / queued bytes.
616      */
617     long pendingOutboundBytes();
618 }