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<Void> 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 }