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 }