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 }