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.netty.channel;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.util.concurrent.DefaultEventExecutorGroup;
20 import io.netty.util.concurrent.EventExecutorGroup;
21 import io.netty.util.concurrent.UnorderedThreadPoolEventExecutor;
22
23 import java.net.SocketAddress;
24 import java.nio.ByteBuffer;
25 import java.nio.channels.SocketChannel;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Map.Entry;
29 import java.util.NoSuchElementException;
30
31
32 /**
33 * A list of {@link ChannelHandler}s which handles or intercepts inbound events and outbound operations of a
34 * {@link Channel}. {@link ChannelPipeline} implements an advanced form of the
35 * <a href="https://www.oracle.com/technetwork/java/interceptingfilter-142169.html">Intercepting Filter</a> pattern
36 * to give a user full control over how an event is handled and how the {@link ChannelHandler}s in a pipeline
37 * interact with each other.
38 *
39 * <h3>Creation of a pipeline</h3>
40 *
41 * Each channel has its own pipeline and it is created automatically when a new channel is created.
42 *
43 * <h3>How an event flows in a pipeline</h3>
44 *
45 * The following diagram describes how I/O events are processed by {@link ChannelHandler}s in a {@link ChannelPipeline}
46 * typically. An I/O event is handled by either a {@link ChannelInboundHandler} or a {@link ChannelOutboundHandler}
47 * and be forwarded to its closest handler by calling the event propagation methods defined in
48 * {@link ChannelHandlerContext}, such as {@link ChannelHandlerContext#fireChannelRead(Object)} and
49 * {@link ChannelHandlerContext#write(Object)}.
50 *
51 * <pre>
52 * I/O Request
53 * via {@link Channel} or
54 * {@link ChannelHandlerContext}
55 * |
56 * +---------------------------------------------------+---------------+
57 * | ChannelPipeline | |
58 * | \|/ |
59 * | +---------------------+ +-----------+----------+ |
60 * | | Inbound Handler N | | Outbound Handler 1 | |
61 * | +----------+----------+ +-----------+----------+ |
62 * | /|\ | |
63 * | | \|/ |
64 * | +----------+----------+ +-----------+----------+ |
65 * | | Inbound Handler N-1 | | Outbound Handler 2 | |
66 * | +----------+----------+ +-----------+----------+ |
67 * | /|\ . |
68 * | . . |
69 * | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
70 * | [ method call] [method call] |
71 * | . . |
72 * | . \|/ |
73 * | +----------+----------+ +-----------+----------+ |
74 * | | Inbound Handler 2 | | Outbound Handler M-1 | |
75 * | +----------+----------+ +-----------+----------+ |
76 * | /|\ | |
77 * | | \|/ |
78 * | +----------+----------+ +-----------+----------+ |
79 * | | Inbound Handler 1 | | Outbound Handler M | |
80 * | +----------+----------+ +-----------+----------+ |
81 * | /|\ | |
82 * +---------------+-----------------------------------+---------------+
83 * | \|/
84 * +---------------+-----------------------------------+---------------+
85 * | | | |
86 * | [ Socket.read() ] [ Socket.write() ] |
87 * | |
88 * | Netty Internal I/O Threads (Transport Implementation) |
89 * +-------------------------------------------------------------------+
90 * </pre>
91 * An inbound event is handled by the inbound handlers in the bottom-up direction as shown on the left side of the
92 * diagram. An inbound handler usually handles the inbound data generated by the I/O thread on the bottom of the
93 * diagram. The inbound data is often read from a remote peer via the actual input operation such as
94 * {@link SocketChannel#read(ByteBuffer)}. If an inbound event goes beyond the top inbound handler, it is discarded
95 * silently, or logged if it needs your attention.
96 * <p>
97 * An outbound event is handled by the outbound handler in the top-down direction as shown on the right side of the
98 * diagram. An outbound handler usually generates or transforms the outbound traffic such as write requests.
99 * If an outbound event goes beyond the bottom outbound handler, it is handled by an I/O thread associated with the
100 * {@link Channel}. The I/O thread often performs the actual output operation such as
101 * {@link SocketChannel#write(ByteBuffer)}.
102 * <p>
103 * For example, let us assume that we created the following pipeline:
104 * <pre>
105 * {@link ChannelPipeline} p = ...;
106 * p.addLast("1", new InboundHandlerA());
107 * p.addLast("2", new InboundHandlerB());
108 * p.addLast("3", new OutboundHandlerA());
109 * p.addLast("4", new OutboundHandlerB());
110 * p.addLast("5", new InboundOutboundHandlerX());
111 * </pre>
112 * In the example above, the class whose name starts with {@code Inbound} means it is an inbound handler.
113 * The class whose name starts with {@code Outbound} means it is a outbound handler.
114 * <p>
115 * In the given example configuration, the handler evaluation order is 1, 2, 3, 4, 5 when an event goes inbound.
116 * When an event goes outbound, the order is 5, 4, 3, 2, 1. On top of this principle, {@link ChannelPipeline} skips
117 * the evaluation of certain handlers to shorten the stack depth:
118 * <ul>
119 * <li>3 and 4 don't implement {@link ChannelInboundHandler}, and therefore the actual evaluation order of an inbound
120 * event will be: 1, 2, and 5.</li>
121 * <li>1 and 2 don't implement {@link ChannelOutboundHandler}, and therefore the actual evaluation order of a
122 * outbound event will be: 5, 4, and 3.</li>
123 * <li>If 5 implements both {@link ChannelInboundHandler} and {@link ChannelOutboundHandler}, the evaluation order of
124 * an inbound and a outbound event could be 125 and 543 respectively.</li>
125 * </ul>
126 *
127 * <h3>Forwarding an event to the next handler</h3>
128 *
129 * As you might noticed in the diagram shows, a handler has to invoke the event propagation methods in
130 * {@link ChannelHandlerContext} to forward an event to its next handler. Those methods include:
131 * <ul>
132 * <li>Inbound event propagation methods:
133 * <ul>
134 * <li>{@link ChannelHandlerContext#fireChannelRegistered()}</li>
135 * <li>{@link ChannelHandlerContext#fireChannelActive()}</li>
136 * <li>{@link ChannelHandlerContext#fireChannelRead(Object)}</li>
137 * <li>{@link ChannelHandlerContext#fireChannelReadComplete()}</li>
138 * <li>{@link ChannelHandlerContext#fireExceptionCaught(Throwable)}</li>
139 * <li>{@link ChannelHandlerContext#fireUserEventTriggered(Object)}</li>
140 * <li>{@link ChannelHandlerContext#fireChannelWritabilityChanged()}</li>
141 * <li>{@link ChannelHandlerContext#fireChannelInactive()}</li>
142 * <li>{@link ChannelHandlerContext#fireChannelUnregistered()}</li>
143 * </ul>
144 * </li>
145 * <li>Outbound event propagation methods:
146 * <ul>
147 * <li>{@link ChannelHandlerContext#bind(SocketAddress, ChannelPromise)}</li>
148 * <li>{@link ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)}</li>
149 * <li>{@link ChannelHandlerContext#write(Object, ChannelPromise)}</li>
150 * <li>{@link ChannelHandlerContext#flush()}</li>
151 * <li>{@link ChannelHandlerContext#read()}</li>
152 * <li>{@link ChannelHandlerContext#disconnect(ChannelPromise)}</li>
153 * <li>{@link ChannelHandlerContext#close(ChannelPromise)}</li>
154 * <li>{@link ChannelHandlerContext#deregister(ChannelPromise)}</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 extends {@link ChannelInboundHandlerAdapter} {
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 extends {@link ChannelOutboundHandlerAdapter} {
171 * {@code @Override}
172 * public void close({@link ChannelHandlerContext} ctx, {@link ChannelPromise} promise) {
173 * System.out.println("Closing ..");
174 * ctx.close(promise);
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 ByteBuf}) 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 * static final {@link EventExecutorGroup} group = new {@link DefaultEventExecutorGroup}(16);
196 * ...
197 *
198 * {@link ChannelPipeline} pipeline = ch.pipeline();
199 *
200 * pipeline.addLast("decoder", new MyProtocolDecoder());
201 * pipeline.addLast("encoder", new MyProtocolEncoder());
202 *
203 * // Tell the pipeline to run MyBusinessLogicHandler's event handler methods
204 * // in a different thread than an I/O thread so that the I/O thread is not blocked by
205 * // a time-consuming task.
206 * // If your business logic is fully asynchronous or finished very quickly, you don't
207 * // need to specify a group.
208 * pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
209 * </pre>
210 *
211 * Be aware that while using {@link DefaultEventLoopGroup} will offload the operation from the {@link EventLoop} it will
212 * still process tasks in a serial fashion per {@link ChannelHandlerContext} and so guarantee ordering. Due the ordering
213 * it may still become a bottle-neck. If ordering is not a requirement for your use-case you may want to consider using
214 * {@link UnorderedThreadPoolEventExecutor} to maximize the parallelism of the task execution.
215 *
216 * <h3>Thread safety</h3>
217 * <p>
218 * A {@link ChannelHandler} can be added or removed at any time because a {@link ChannelPipeline} is thread safe.
219 * For example, you can insert an encryption handler when sensitive information is about to be exchanged, and remove it
220 * after the exchange.
221 */
222 public interface ChannelPipeline
223 extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable<Entry<String, ChannelHandler>> {
224
225 /**
226 * Inserts a {@link ChannelHandler} at the first position of this pipeline.
227 *
228 * @param name the name of the handler to insert first
229 * @param handler the handler to insert first
230 *
231 * @throws IllegalArgumentException
232 * if there's an entry with the same name already in the pipeline
233 * @throws NullPointerException
234 * if the specified handler is {@code null}
235 */
236 ChannelPipeline addFirst(String name, ChannelHandler handler);
237
238 /**
239 * Inserts a {@link ChannelHandler} at the first position of this pipeline.
240 *
241 * @param group the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}
242 * methods
243 * @param name the name of the handler to insert first
244 * @param handler the handler to insert first
245 *
246 * @throws IllegalArgumentException
247 * if there's an entry with the same name already in the pipeline
248 * @throws NullPointerException
249 * if the specified handler is {@code null}
250 */
251 ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler);
252
253 /**
254 * Appends a {@link ChannelHandler} at the last position of this pipeline.
255 *
256 * @param name the name of the handler to append
257 * @param handler the handler to append
258 *
259 * @throws IllegalArgumentException
260 * if there's an entry with the same name already in the pipeline
261 * @throws NullPointerException
262 * if the specified handler is {@code null}
263 */
264 ChannelPipeline addLast(String name, ChannelHandler handler);
265
266 /**
267 * Appends a {@link ChannelHandler} at the last position of this pipeline.
268 *
269 * @param group the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}
270 * methods
271 * @param name the name of the handler to append
272 * @param handler the handler to append
273 *
274 * @throws IllegalArgumentException
275 * if there's an entry with the same name already in the pipeline
276 * @throws NullPointerException
277 * if the specified handler is {@code null}
278 */
279 ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler);
280
281 /**
282 * Inserts a {@link ChannelHandler} before an existing handler of this
283 * pipeline.
284 *
285 * @param baseName the name of the existing handler
286 * @param name the name of the handler to insert before
287 * @param handler the handler to insert before
288 *
289 * @throws NoSuchElementException
290 * if there's no such entry with the specified {@code baseName}
291 * @throws IllegalArgumentException
292 * if there's an entry with the same name already in the pipeline
293 * @throws NullPointerException
294 * if the specified baseName or handler is {@code null}
295 */
296 ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);
297
298 /**
299 * Inserts a {@link ChannelHandler} before an existing handler of this
300 * pipeline.
301 *
302 * @param group the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}
303 * methods
304 * @param baseName the name of the existing handler
305 * @param name the name of the handler to insert before
306 * @param handler the handler to insert before
307 *
308 * @throws NoSuchElementException
309 * if there's no such entry with the specified {@code baseName}
310 * @throws IllegalArgumentException
311 * if there's an entry with the same name already in the pipeline
312 * @throws NullPointerException
313 * if the specified baseName or handler is {@code null}
314 */
315 ChannelPipeline addBefore(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);
316
317 /**
318 * Inserts a {@link ChannelHandler} after an existing handler of this
319 * pipeline.
320 *
321 * @param baseName the name of the existing handler
322 * @param name the name of the handler to insert after
323 * @param handler the handler to insert after
324 *
325 * @throws NoSuchElementException
326 * if there's no such entry with the specified {@code baseName}
327 * @throws IllegalArgumentException
328 * if there's an entry with the same name already in the pipeline
329 * @throws NullPointerException
330 * if the specified baseName or handler is {@code null}
331 */
332 ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);
333
334 /**
335 * Inserts a {@link ChannelHandler} after an existing handler of this
336 * pipeline.
337 *
338 * @param group the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}
339 * methods
340 * @param baseName the name of the existing handler
341 * @param name the name of the handler to insert after
342 * @param handler the handler to insert after
343 *
344 * @throws NoSuchElementException
345 * if there's no such entry with the specified {@code baseName}
346 * @throws IllegalArgumentException
347 * if there's an entry with the same name already in the pipeline
348 * @throws NullPointerException
349 * if the specified baseName or handler is {@code null}
350 */
351 ChannelPipeline addAfter(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);
352
353 /**
354 * Inserts {@link ChannelHandler}s at the first position of this pipeline.
355 *
356 * @param handlers the handlers to insert first
357 *
358 */
359 ChannelPipeline addFirst(ChannelHandler... handlers);
360
361 /**
362 * Inserts {@link ChannelHandler}s at the first position of this pipeline.
363 *
364 * @param group the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}s
365 * methods.
366 * @param handlers the handlers to insert first
367 *
368 */
369 ChannelPipeline addFirst(EventExecutorGroup group, ChannelHandler... handlers);
370
371 /**
372 * Inserts {@link ChannelHandler}s at the last position of this pipeline.
373 *
374 * @param handlers the handlers to insert last
375 *
376 */
377 ChannelPipeline addLast(ChannelHandler... handlers);
378
379 /**
380 * Inserts {@link ChannelHandler}s at the last position of this pipeline.
381 *
382 * @param group the {@link EventExecutorGroup} which will be used to execute the {@link ChannelHandler}s
383 * methods.
384 * @param handlers the handlers to insert last
385 *
386 */
387 ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler... handlers);
388
389 /**
390 * Removes the specified {@link ChannelHandler} from this pipeline.
391 *
392 * @param handler the {@link ChannelHandler} to remove
393 *
394 * @throws NoSuchElementException
395 * if there's no such handler in this pipeline
396 * @throws NullPointerException
397 * if the specified handler is {@code null}
398 */
399 ChannelPipeline remove(ChannelHandler handler);
400
401 /**
402 * Removes the {@link ChannelHandler} with the specified name from this pipeline.
403 *
404 * @param name the name under which the {@link ChannelHandler} was stored.
405 *
406 * @return the removed handler
407 *
408 * @throws NoSuchElementException
409 * if there's no such handler with the specified name in this pipeline
410 * @throws NullPointerException
411 * if the specified name is {@code null}
412 */
413 ChannelHandler remove(String name);
414
415 /**
416 * Removes the {@link ChannelHandler} of the specified type from this pipeline.
417 *
418 * @param <T> the type of the handler
419 * @param handlerType the type of the handler
420 *
421 * @return the removed handler
422 *
423 * @throws NoSuchElementException
424 * if there's no such handler of the specified type in this pipeline
425 * @throws NullPointerException
426 * if the specified handler type is {@code null}
427 */
428 <T extends ChannelHandler> T remove(Class<T> handlerType);
429
430 /**
431 * Removes the first {@link ChannelHandler} in this pipeline.
432 *
433 * @return the removed handler
434 *
435 * @throws NoSuchElementException
436 * if this pipeline is empty
437 */
438 ChannelHandler removeFirst();
439
440 /**
441 * Removes the last {@link ChannelHandler} in this pipeline.
442 *
443 * @return the removed handler
444 *
445 * @throws NoSuchElementException
446 * if this pipeline is empty
447 */
448 ChannelHandler removeLast();
449
450 /**
451 * Replaces the specified {@link ChannelHandler} with a new handler in this pipeline.
452 *
453 * @param oldHandler the {@link ChannelHandler} to be replaced
454 * @param newName the name under which the replacement should be added
455 * @param newHandler the {@link ChannelHandler} which is used as replacement
456 *
457 * @return itself
458
459 * @throws NoSuchElementException
460 * if the specified old handler does not exist 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 ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);
469
470 /**
471 * Replaces the {@link ChannelHandler} of the specified name with a new handler in this pipeline.
472 *
473 * @param oldName the name of the {@link ChannelHandler} to be replaced
474 * @param newName the name under which the replacement should be added
475 * @param newHandler the {@link ChannelHandler} which is used as replacement
476 *
477 * @return the removed handler
478 *
479 * @throws NoSuchElementException
480 * if the handler with the specified old name does not exist in this pipeline
481 * @throws IllegalArgumentException
482 * if a handler with the specified new name already exists in this
483 * pipeline, except for the handler to be replaced
484 * @throws NullPointerException
485 * if the specified old handler or new handler is
486 * {@code null}
487 */
488 ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);
489
490 /**
491 * Replaces the {@link ChannelHandler} of the specified type with a new handler in this pipeline.
492 *
493 * @param oldHandlerType the type of the handler to be removed
494 * @param newName the name under which the replacement should be added
495 * @param newHandler the {@link ChannelHandler} which is used as replacement
496 *
497 * @return the removed handler
498 *
499 * @throws NoSuchElementException
500 * if the handler of the specified old handler type does not exist
501 * in this pipeline
502 * @throws IllegalArgumentException
503 * if a handler with the specified new name already exists in this
504 * pipeline, except for the handler to be replaced
505 * @throws NullPointerException
506 * if the specified old handler or new handler is
507 * {@code null}
508 */
509 <T extends ChannelHandler> T replace(Class<T> oldHandlerType, String newName,
510 ChannelHandler newHandler);
511
512 /**
513 * Returns the first {@link ChannelHandler} in this pipeline.
514 *
515 * @return the first handler. {@code null} if this pipeline is empty.
516 */
517 ChannelHandler first();
518
519 /**
520 * Returns the context of the first {@link ChannelHandler} in this pipeline.
521 *
522 * @return the context of the first handler. {@code null} if this pipeline is empty.
523 */
524 ChannelHandlerContext firstContext();
525
526 /**
527 * Returns the last {@link ChannelHandler} in this pipeline.
528 *
529 * @return the last handler. {@code null} if this pipeline is empty.
530 */
531 ChannelHandler last();
532
533 /**
534 * Returns the context of the last {@link ChannelHandler} in this pipeline.
535 *
536 * @return the context of the last handler. {@code null} if this pipeline is empty.
537 */
538 ChannelHandlerContext lastContext();
539
540 /**
541 * Returns the {@link ChannelHandler} with the specified name in this
542 * pipeline.
543 *
544 * @return the handler with the specified name.
545 * {@code null} if there's no such handler in this pipeline.
546 */
547 ChannelHandler get(String name);
548
549 /**
550 * Returns the {@link ChannelHandler} of the specified type in this
551 * pipeline.
552 *
553 * @return the handler of the specified handler type.
554 * {@code null} if there's no such handler in this pipeline.
555 */
556 <T extends ChannelHandler> T get(Class<T> handlerType);
557
558 /**
559 * Returns the context object of the specified {@link ChannelHandler} in
560 * this pipeline.
561 *
562 * @return the context object of the specified handler.
563 * {@code null} if there's no such handler in this pipeline.
564 */
565 ChannelHandlerContext context(ChannelHandler handler);
566
567 /**
568 * Returns the context object of the {@link ChannelHandler} with the
569 * specified name in this pipeline.
570 *
571 * @return the context object of the handler with the specified name.
572 * {@code null} if there's no such handler in this pipeline.
573 */
574 ChannelHandlerContext context(String name);
575
576 /**
577 * Returns the context object of the {@link ChannelHandler} of the
578 * specified type in this pipeline.
579 *
580 * @return the context object of the handler of the specified type.
581 * {@code null} if there's no such handler in this pipeline.
582 */
583 ChannelHandlerContext context(Class<? extends ChannelHandler> handlerType);
584
585 /**
586 * Returns the {@link Channel} that this pipeline is attached to.
587 *
588 * @return the channel. {@code null} if this pipeline is not attached yet.
589 */
590 Channel channel();
591
592 /**
593 * Returns the {@link List} of the handler names.
594 */
595 List<String> names();
596
597 /**
598 * Converts this pipeline into an ordered {@link Map} whose keys are
599 * handler names and whose values are handlers.
600 */
601 Map<String, ChannelHandler> toMap();
602
603 @Override
604 ChannelPipeline fireChannelRegistered();
605
606 @Override
607 ChannelPipeline fireChannelUnregistered();
608
609 @Override
610 ChannelPipeline fireChannelActive();
611
612 @Override
613 ChannelPipeline fireChannelInactive();
614
615 @Override
616 ChannelPipeline fireExceptionCaught(Throwable cause);
617
618 @Override
619 ChannelPipeline fireUserEventTriggered(Object event);
620
621 @Override
622 ChannelPipeline fireChannelRead(Object msg);
623
624 @Override
625 ChannelPipeline fireChannelReadComplete();
626
627 @Override
628 ChannelPipeline fireChannelWritabilityChanged();
629
630 @Override
631 ChannelPipeline flush();
632 }