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 * http://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 org.jboss.netty.channel; 17 18 import java.net.SocketAddress; 19 import java.util.Map; 20 21 import org.jboss.netty.util.internal.ConversionUtil; 22 23 24 /** 25 * A helper class which provides various convenience methods related with 26 * {@link Channel}, {@link ChannelHandler}, and {@link ChannelPipeline}. 27 * 28 * <h3>Factory methods</h3> 29 * <p> 30 * It is always recommended to use the factory methods provided by 31 * {@link Channels} rather than calling the constructor of the implementation 32 * types. 33 * <ul> 34 * <li>{@link #pipeline()}</li> 35 * <li>{@link #pipeline(ChannelPipeline)}</li> 36 * <li>{@link #pipelineFactory(ChannelPipeline)}</li> 37 * <li>{@link #succeededFuture(Channel)}</li> 38 * <li>{@link #failedFuture(Channel, Throwable)}</li> 39 * </ul> 40 * 41 * <h3>Upstream and downstream event generation</h3> 42 * <p> 43 * Various event generation methods are provided to simplify the generation of 44 * upstream events and downstream events. It is always recommended to use the 45 * event generation methods provided by {@link Channels} rather than calling 46 * {@link ChannelHandlerContext#sendUpstream(ChannelEvent)} or 47 * {@link ChannelHandlerContext#sendDownstream(ChannelEvent)} by yourself. 48 * @apiviz.landmark 49 */ 50 public final class Channels { 51 52 // pipeline factory methods 53 54 /** 55 * Creates a new {@link ChannelPipeline}. 56 */ 57 public static ChannelPipeline pipeline() { 58 return new DefaultChannelPipeline(); 59 } 60 61 /** 62 * Creates a new {@link ChannelPipeline} which contains the specified 63 * {@link ChannelHandler}s. The names of the specified handlers are 64 * generated automatically; the first handler's name is {@code "0"}, 65 * the second handler's name is {@code "1"}, the third handler's name is 66 * {@code "2"}, and so on. 67 */ 68 public static ChannelPipeline pipeline(ChannelHandler... handlers) { 69 if (handlers == null) { 70 throw new NullPointerException("handlers"); 71 } 72 73 ChannelPipeline newPipeline = pipeline(); 74 for (int i = 0; i < handlers.length; i ++) { 75 ChannelHandler h = handlers[i]; 76 if (h == null) { 77 break; 78 } 79 newPipeline.addLast(ConversionUtil.toString(i), h); 80 } 81 return newPipeline; 82 } 83 84 /** 85 * Creates a new {@link ChannelPipeline} which contains the same entries 86 * with the specified {@code pipeline}. Please note that only the names 87 * and the references of the {@link ChannelHandler}s will be copied; a new 88 * {@link ChannelHandler} instance will never be created. 89 */ 90 public static ChannelPipeline pipeline(ChannelPipeline pipeline) { 91 ChannelPipeline newPipeline = pipeline(); 92 for (Map.Entry<String, ChannelHandler> e: pipeline.toMap().entrySet()) { 93 newPipeline.addLast(e.getKey(), e.getValue()); 94 } 95 return newPipeline; 96 } 97 98 /** 99 * Creates a new {@link ChannelPipelineFactory} which creates a new 100 * {@link ChannelPipeline} which contains the same entries with the 101 * specified {@code pipeline}. Please note that only the names and the 102 * references of the {@link ChannelHandler}s will be copied; a new 103 * {@link ChannelHandler} instance will never be created. 104 */ 105 public static ChannelPipelineFactory pipelineFactory( 106 final ChannelPipeline pipeline) { 107 return new ChannelPipelineFactory() { 108 public ChannelPipeline getPipeline() { 109 return pipeline(pipeline); 110 } 111 }; 112 } 113 114 // future factory methods 115 116 /** 117 * Creates a new non-cancellable {@link ChannelFuture} for the specified 118 * {@link Channel}. 119 */ 120 public static ChannelFuture future(Channel channel) { 121 return future(channel, false); 122 } 123 124 /** 125 * Creates a new {@link ChannelFuture} for the specified {@link Channel}. 126 * 127 * @param cancellable {@code true} if and only if the returned future 128 * can be canceled by {@link ChannelFuture#cancel()} 129 */ 130 public static ChannelFuture future(Channel channel, boolean cancellable) { 131 return new DefaultChannelFuture(channel, cancellable); 132 } 133 134 /** 135 * Creates a new {@link ChannelFuture} which is already succeeded for the 136 * specified {@link Channel}. 137 */ 138 public static ChannelFuture succeededFuture(Channel channel) { 139 if (channel instanceof AbstractChannel) { 140 return ((AbstractChannel) channel).getSucceededFuture(); 141 } else { 142 return new SucceededChannelFuture(channel); 143 } 144 } 145 146 /** 147 * Creates a new {@link ChannelFuture} which has failed already for the 148 * specified {@link Channel}. 149 * 150 * @param cause the cause of the failure 151 */ 152 public static ChannelFuture failedFuture(Channel channel, Throwable cause) { 153 return new FailedChannelFuture(channel, cause); 154 } 155 156 // event emission methods 157 158 /** 159 * Sends a {@code "channelOpen"} event to the first 160 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 161 * the specified {@link Channel}. If the specified channel has a parent, 162 * a {@code "childChannelOpen"} event will be sent, too. 163 */ 164 public static void fireChannelOpen(Channel channel) { 165 // Notify the parent handler. 166 if (channel.getParent() != null) { 167 fireChildChannelStateChanged(channel.getParent(), channel); 168 } 169 170 channel.getPipeline().sendUpstream( 171 new UpstreamChannelStateEvent( 172 channel, ChannelState.OPEN, Boolean.TRUE)); 173 } 174 175 /** 176 * Sends a {@code "channelOpen"} event to the 177 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 178 * from the handler associated with the specified 179 * {@link ChannelHandlerContext}. 180 * <p> 181 * Please note that this method does not trigger a 182 * {@code "childChannelOpen"} event unlike {@link #fireChannelOpen(Channel)} 183 * method. 184 */ 185 public static void fireChannelOpen(ChannelHandlerContext ctx) { 186 ctx.sendUpstream(new UpstreamChannelStateEvent( 187 ctx.getChannel(), ChannelState.OPEN, Boolean.TRUE)); 188 } 189 190 /** 191 * Sends a {@code "channelBound"} event to the first 192 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 193 * the specified {@link Channel}. 194 * 195 * @param localAddress 196 * the local address where the specified channel is bound 197 */ 198 public static void fireChannelBound(Channel channel, SocketAddress localAddress) { 199 channel.getPipeline().sendUpstream( 200 new UpstreamChannelStateEvent( 201 channel, ChannelState.BOUND, localAddress)); 202 } 203 204 /** 205 * Sends a {@code "channelBound"} event to the 206 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 207 * from the handler associated with the specified 208 * {@link ChannelHandlerContext}. 209 * 210 * @param localAddress 211 * the local address where the specified channel is bound 212 */ 213 public static void fireChannelBound(ChannelHandlerContext ctx, SocketAddress localAddress) { 214 ctx.sendUpstream(new UpstreamChannelStateEvent( 215 ctx.getChannel(), ChannelState.BOUND, localAddress)); 216 } 217 218 /** 219 * Sends a {@code "channelConnected"} event to the first 220 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 221 * the specified {@link Channel}. 222 * 223 * @param remoteAddress 224 * the remote address where the specified channel is connected 225 */ 226 public static void fireChannelConnected(Channel channel, SocketAddress remoteAddress) { 227 channel.getPipeline().sendUpstream( 228 new UpstreamChannelStateEvent( 229 channel, ChannelState.CONNECTED, remoteAddress)); 230 } 231 232 /** 233 * Sends a {@code "channelConnected"} event to the 234 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 235 * from the handler associated with the specified 236 * {@link ChannelHandlerContext}. 237 * 238 * @param remoteAddress 239 * the remote address where the specified channel is connected 240 */ 241 public static void fireChannelConnected(ChannelHandlerContext ctx, SocketAddress remoteAddress) { 242 243 ctx.sendUpstream(new UpstreamChannelStateEvent( 244 ctx.getChannel(), ChannelState.CONNECTED, remoteAddress)); 245 } 246 247 /** 248 * Sends a {@code "messageReceived"} event to the first 249 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 250 * the specified {@link Channel}. 251 * 252 * @param message the received message 253 */ 254 public static void fireMessageReceived(Channel channel, Object message) { 255 fireMessageReceived(channel, message, null); 256 } 257 258 /** 259 * Sends a {@code "messageReceived"} event to the first 260 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 261 * the specified {@link Channel} belongs. 262 * 263 * @param message the received message 264 * @param remoteAddress the remote address where the received message 265 * came from 266 */ 267 public static void fireMessageReceived(Channel channel, Object message, SocketAddress remoteAddress) { 268 channel.getPipeline().sendUpstream( 269 new UpstreamMessageEvent(channel, message, remoteAddress)); 270 } 271 272 /** 273 * Sends a {@code "messageReceived"} event to the 274 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 275 * from the handler associated with the specified 276 * {@link ChannelHandlerContext}. 277 * 278 * @param message the received message 279 */ 280 public static void fireMessageReceived(ChannelHandlerContext ctx, Object message) { 281 ctx.sendUpstream(new UpstreamMessageEvent(ctx.getChannel(), message, null)); 282 } 283 284 /** 285 * Sends a {@code "messageReceived"} event to the 286 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 287 * from the handler associated with the specified 288 * {@link ChannelHandlerContext}. 289 * 290 * @param message the received message 291 * @param remoteAddress the remote address where the received message 292 * came from 293 */ 294 public static void fireMessageReceived( 295 ChannelHandlerContext ctx, Object message, SocketAddress remoteAddress) { 296 ctx.sendUpstream(new UpstreamMessageEvent( 297 ctx.getChannel(), message, remoteAddress)); 298 } 299 300 /** 301 * Sends a {@code "writeComplete"} event to the first 302 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 303 * the specified {@link Channel} in the next io-thread. 304 */ 305 public static ChannelFuture fireWriteCompleteLater(final Channel channel, final long amount) { 306 return channel.getPipeline().execute(new Runnable() { 307 308 public void run() { 309 fireWriteComplete(channel, amount); 310 } 311 }); 312 } 313 314 /** 315 * Sends a {@code "writeComplete"} event to the first 316 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 317 * the specified {@link Channel}. 318 */ 319 public static void fireWriteComplete(Channel channel, long amount) { 320 if (amount == 0) { 321 return; 322 } 323 324 channel.getPipeline().sendUpstream( 325 new DefaultWriteCompletionEvent(channel, amount)); 326 } 327 328 /** 329 * Sends a {@code "writeComplete"} event to the 330 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 331 * from the handler associated with the specified 332 * {@link ChannelHandlerContext}. 333 */ 334 public static void fireWriteComplete(ChannelHandlerContext ctx, long amount) { 335 ctx.sendUpstream(new DefaultWriteCompletionEvent(ctx.getChannel(), amount)); 336 } 337 338 /** 339 * Sends a {@code "channelInterestChanged"} event to the first 340 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 341 * the specified {@link Channel} once the io-thread runs again. 342 */ 343 public static ChannelFuture fireChannelInterestChangedLater(final Channel channel) { 344 return channel.getPipeline().execute(new Runnable() { 345 346 public void run() { 347 fireChannelInterestChanged(channel); 348 } 349 }); 350 } 351 352 /** 353 * Sends a {@code "channelInterestChanged"} event to the first 354 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 355 * the specified {@link Channel}. 356 */ 357 public static void fireChannelInterestChanged(Channel channel) { 358 channel.getPipeline().sendUpstream( 359 new UpstreamChannelStateEvent( 360 channel, ChannelState.INTEREST_OPS, Channel.OP_READ)); 361 } 362 363 /** 364 * Sends a {@code "channelInterestChanged"} event to the 365 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 366 * from the handler associated with the specified 367 * {@link ChannelHandlerContext}. 368 */ 369 public static void fireChannelInterestChanged( 370 ChannelHandlerContext ctx) { 371 372 ctx.sendUpstream( 373 new UpstreamChannelStateEvent( 374 ctx.getChannel(), ChannelState.INTEREST_OPS, Channel.OP_READ)); 375 } 376 377 /** 378 * Sends a {@code "channelDisconnected"} event to the first 379 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 380 * the specified {@link Channel} once the io-thread runs again. 381 */ 382 public static ChannelFuture fireChannelDisconnectedLater(final Channel channel) { 383 return channel.getPipeline().execute(new Runnable() { 384 385 public void run() { 386 fireChannelDisconnected(channel); 387 } 388 }); 389 } 390 /** 391 * Sends a {@code "channelDisconnected"} event to the first 392 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 393 * the specified {@link Channel}. 394 */ 395 public static void fireChannelDisconnected(Channel channel) { 396 channel.getPipeline().sendUpstream( 397 new UpstreamChannelStateEvent( 398 channel, ChannelState.CONNECTED, null)); 399 } 400 401 /** 402 * Sends a {@code "channelDisconnected"} event to the 403 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 404 * from the handler associated with the specified 405 * {@link ChannelHandlerContext}. 406 */ 407 public static void fireChannelDisconnected(ChannelHandlerContext ctx) { 408 ctx.sendUpstream(new UpstreamChannelStateEvent( 409 ctx.getChannel(), ChannelState.CONNECTED, null)); 410 } 411 412 /** 413 * Sends a {@code "channelUnbound"} event to the first 414 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 415 * the specified {@link Channel} once the io-thread runs again. 416 */ 417 public static ChannelFuture fireChannelUnboundLater(final Channel channel) { 418 return channel.getPipeline().execute(new Runnable() { 419 420 public void run() { 421 fireChannelUnbound(channel); 422 } 423 }); 424 } 425 426 /** 427 * Sends a {@code "channelUnbound"} event to the first 428 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 429 * the specified {@link Channel}. 430 */ 431 public static void fireChannelUnbound(Channel channel) { 432 channel.getPipeline().sendUpstream(new UpstreamChannelStateEvent( 433 channel, ChannelState.BOUND, null)); 434 } 435 436 /** 437 * Sends a {@code "channelUnbound"} event to the 438 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 439 * from the handler associated with the specified 440 * {@link ChannelHandlerContext}. 441 */ 442 public static void fireChannelUnbound(ChannelHandlerContext ctx) { 443 444 ctx.sendUpstream(new UpstreamChannelStateEvent( 445 ctx.getChannel(), ChannelState.BOUND, null)); 446 } 447 448 /** 449 * Sends a {@code "channelClosed"} event to the first 450 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 451 * the specified {@link Channel} once the io-thread runs again. 452 */ 453 public static ChannelFuture fireChannelClosedLater(final Channel channel) { 454 return channel.getPipeline().execute(new Runnable() { 455 456 public void run() { 457 fireChannelClosed(channel); 458 } 459 }); 460 } 461 462 /** 463 * Sends a {@code "channelClosed"} event to the first 464 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 465 * the specified {@link Channel}. 466 */ 467 public static void fireChannelClosed(Channel channel) { 468 channel.getPipeline().sendUpstream( 469 new UpstreamChannelStateEvent( 470 channel, ChannelState.OPEN, Boolean.FALSE)); 471 472 // Notify the parent handler. 473 if (channel.getParent() != null) { 474 fireChildChannelStateChanged(channel.getParent(), channel); 475 } 476 } 477 478 /** 479 * Sends a {@code "channelClosed"} event to the 480 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 481 * from the handler associated with the specified 482 * {@link ChannelHandlerContext}. 483 */ 484 public static void fireChannelClosed(ChannelHandlerContext ctx) { 485 ctx.sendUpstream( 486 new UpstreamChannelStateEvent( 487 ctx.getChannel(), ChannelState.OPEN, Boolean.FALSE)); 488 } 489 490 /** 491 * Sends a {@code "exceptionCaught"} event to the first 492 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 493 * the specified {@link Channel} once the io-thread runs again. 494 */ 495 public static ChannelFuture fireExceptionCaughtLater(final Channel channel, final Throwable cause) { 496 return channel.getPipeline().execute(new Runnable() { 497 498 public void run() { 499 fireExceptionCaught(channel, cause); 500 } 501 }); 502 } 503 504 /** 505 * Sends a {@code "exceptionCaught"} event to the 506 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 507 * from the handler associated with the specified 508 * {@link ChannelHandlerContext} once the io-thread runs again. 509 */ 510 public static ChannelFuture fireExceptionCaughtLater(final ChannelHandlerContext ctx, final Throwable cause) { 511 return ctx.getPipeline().execute(new Runnable() { 512 513 public void run() { 514 fireExceptionCaught(ctx, cause); 515 } 516 }); 517 } 518 519 /** 520 * Sends a {@code "exceptionCaught"} event to the first 521 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 522 * the specified {@link Channel}. 523 */ 524 public static void fireExceptionCaught(Channel channel, Throwable cause) { 525 channel.getPipeline().sendUpstream( 526 new DefaultExceptionEvent(channel, cause)); 527 } 528 529 /** 530 * Sends a {@code "exceptionCaught"} event to the 531 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 532 * from the handler associated with the specified 533 * {@link ChannelHandlerContext}. 534 */ 535 public static void fireExceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 536 ctx.sendUpstream(new DefaultExceptionEvent(ctx.getChannel(), cause)); 537 } 538 539 private static void fireChildChannelStateChanged( 540 Channel channel, Channel childChannel) { 541 channel.getPipeline().sendUpstream( 542 new DefaultChildChannelStateEvent(channel, childChannel)); 543 } 544 545 /** 546 * Sends a {@code "bind"} request to the last 547 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 548 * the specified {@link Channel}. 549 * 550 * @param channel the channel to bind 551 * @param localAddress the local address to bind to 552 * 553 * @return the {@link ChannelFuture} which will be notified when the 554 * bind operation is done 555 */ 556 public static ChannelFuture bind(Channel channel, SocketAddress localAddress) { 557 if (localAddress == null) { 558 throw new NullPointerException("localAddress"); 559 } 560 ChannelFuture future = future(channel); 561 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 562 channel, future, ChannelState.BOUND, localAddress)); 563 return future; 564 } 565 566 /** 567 * Sends a {@code "bind"} request to the 568 * {@link ChannelDownstreamHandler} which is placed in the closest 569 * downstream from the handler associated with the specified 570 * {@link ChannelHandlerContext}. 571 * 572 * @param ctx the context 573 * @param future the future which will be notified when the bind 574 * operation is done 575 * @param localAddress the local address to bind to 576 */ 577 public static void bind( 578 ChannelHandlerContext ctx, ChannelFuture future, SocketAddress localAddress) { 579 if (localAddress == null) { 580 throw new NullPointerException("localAddress"); 581 } 582 ctx.sendDownstream(new DownstreamChannelStateEvent( 583 ctx.getChannel(), future, ChannelState.BOUND, localAddress)); 584 } 585 586 /** 587 * Sends a {@code "unbind"} request to the 588 * {@link ChannelDownstreamHandler} which is placed in the closest 589 * downstream from the handler associated with the specified 590 * {@link ChannelHandlerContext}. 591 * 592 * @param ctx the context 593 * @param future the future which will be notified when the unbind 594 * operation is done 595 */ 596 public static void unbind(ChannelHandlerContext ctx, ChannelFuture future) { 597 ctx.sendDownstream(new DownstreamChannelStateEvent( 598 ctx.getChannel(), future, ChannelState.BOUND, null)); 599 } 600 601 /** 602 * Sends a {@code "unbind"} request to the last 603 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 604 * the specified {@link Channel}. 605 * 606 * @param channel the channel to unbind 607 * 608 * @return the {@link ChannelFuture} which will be notified when the 609 * unbind operation is done 610 */ 611 public static ChannelFuture unbind(Channel channel) { 612 ChannelFuture future = future(channel); 613 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 614 channel, future, ChannelState.BOUND, null)); 615 return future; 616 } 617 618 /** 619 * Sends a {@code "connect"} request to the last 620 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 621 * the specified {@link Channel}. 622 * 623 * @param channel the channel to attempt a connection 624 * @param remoteAddress the remote address to connect to 625 * 626 * @return the {@link ChannelFuture} which will be notified when the 627 * connection attempt is done 628 */ 629 public static ChannelFuture connect(Channel channel, SocketAddress remoteAddress) { 630 if (remoteAddress == null) { 631 throw new NullPointerException("remoteAddress"); 632 } 633 ChannelFuture future = future(channel, true); 634 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 635 channel, future, ChannelState.CONNECTED, remoteAddress)); 636 return future; 637 } 638 639 /** 640 * Sends a {@code "connect"} request to the 641 * {@link ChannelDownstreamHandler} which is placed in the closest 642 * downstream from the handler associated with the specified 643 * {@link ChannelHandlerContext}. 644 * 645 * @param ctx the context 646 * @param future the future which will be notified when the connection 647 * attempt is done 648 * @param remoteAddress the remote address to connect to 649 */ 650 public static void connect( 651 ChannelHandlerContext ctx, ChannelFuture future, SocketAddress remoteAddress) { 652 if (remoteAddress == null) { 653 throw new NullPointerException("remoteAddress"); 654 } 655 ctx.sendDownstream(new DownstreamChannelStateEvent( 656 ctx.getChannel(), future, ChannelState.CONNECTED, remoteAddress)); 657 } 658 659 /** 660 * Sends a {@code "write"} request to the last 661 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 662 * the specified {@link Channel}. 663 * 664 * @param channel the channel to write a message 665 * @param message the message to write to the channel 666 * 667 * @return the {@link ChannelFuture} which will be notified when the 668 * write operation is done 669 */ 670 public static ChannelFuture write(Channel channel, Object message) { 671 return write(channel, message, null); 672 } 673 674 /** 675 * Sends a {@code "write"} request to the 676 * {@link ChannelDownstreamHandler} which is placed in the closest 677 * downstream from the handler associated with the specified 678 * {@link ChannelHandlerContext}. 679 * 680 * @param ctx the context 681 * @param future the future which will be notified when the write 682 * operation is done 683 */ 684 public static void write( 685 ChannelHandlerContext ctx, ChannelFuture future, Object message) { 686 write(ctx, future, message, null); 687 } 688 689 /** 690 * Sends a {@code "write"} request to the last 691 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 692 * the specified {@link Channel}. 693 * 694 * @param channel the channel to write a message 695 * @param message the message to write to the channel 696 * @param remoteAddress the destination of the message. 697 * {@code null} to use the default remote address 698 * 699 * @return the {@link ChannelFuture} which will be notified when the 700 * write operation is done 701 */ 702 public static ChannelFuture write(Channel channel, Object message, SocketAddress remoteAddress) { 703 ChannelFuture future = future(channel); 704 channel.getPipeline().sendDownstream( 705 new DownstreamMessageEvent(channel, future, message, remoteAddress)); 706 return future; 707 } 708 709 /** 710 * Sends a {@code "write"} request to the 711 * {@link ChannelDownstreamHandler} which is placed in the closest 712 * downstream from the handler associated with the specified 713 * {@link ChannelHandlerContext}. 714 * 715 * @param ctx the context 716 * @param future the future which will be notified when the write 717 * operation is done 718 * @param message the message to write to the channel 719 * @param remoteAddress the destination of the message. 720 * {@code null} to use the default remote address. 721 */ 722 public static void write( 723 ChannelHandlerContext ctx, ChannelFuture future, 724 Object message, SocketAddress remoteAddress) { 725 ctx.sendDownstream( 726 new DownstreamMessageEvent(ctx.getChannel(), future, message, remoteAddress)); 727 } 728 729 /** 730 * Sends a {@code "setInterestOps"} request to the last 731 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 732 * the specified {@link Channel}. 733 * 734 * @param channel the channel to change its interestOps 735 * @param interestOps the new interestOps 736 * 737 * @return the {@link ChannelFuture} which will be notified when the 738 * interestOps is changed 739 */ 740 public static ChannelFuture setInterestOps(Channel channel, int interestOps) { 741 validateInterestOps(interestOps); 742 interestOps = filterDownstreamInterestOps(interestOps); 743 744 ChannelFuture future = future(channel); 745 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 746 channel, future, ChannelState.INTEREST_OPS, interestOps)); 747 return future; 748 } 749 750 /** 751 * Sends a {@code "setInterestOps"} request to the 752 * {@link ChannelDownstreamHandler} which is placed in the closest 753 * downstream from the handler associated with the specified 754 * {@link ChannelHandlerContext}. 755 * 756 * @param ctx the context 757 * @param future the future which will be notified when the interestOps is 758 * changed. 759 */ 760 public static void setInterestOps( 761 ChannelHandlerContext ctx, ChannelFuture future, int interestOps) { 762 validateInterestOps(interestOps); 763 interestOps = filterDownstreamInterestOps(interestOps); 764 765 ctx.sendDownstream( 766 new DownstreamChannelStateEvent( 767 ctx.getChannel(), future, ChannelState.INTEREST_OPS, interestOps)); 768 } 769 770 /** 771 * Sends a {@code "disconnect"} request to the last 772 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 773 * the specified {@link Channel}. 774 * 775 * @param channel the channel to disconnect 776 * 777 * @return the {@link ChannelFuture} which will be notified on disconnection 778 */ 779 public static ChannelFuture disconnect(Channel channel) { 780 ChannelFuture future = future(channel); 781 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 782 channel, future, ChannelState.CONNECTED, null)); 783 return future; 784 } 785 786 /** 787 * Sends a {@code "disconnect"} request to the 788 * {@link ChannelDownstreamHandler} which is placed in the closest 789 * downstream from the handler associated with the specified 790 * {@link ChannelHandlerContext}. 791 * 792 * @param ctx the context 793 * @param future the future which will be notified on disconnection 794 */ 795 public static void disconnect( 796 ChannelHandlerContext ctx, ChannelFuture future) { 797 ctx.sendDownstream(new DownstreamChannelStateEvent( 798 ctx.getChannel(), future, ChannelState.CONNECTED, null)); 799 } 800 801 /** 802 * Sends a {@code "close"} request to the last 803 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 804 * the specified {@link Channel}. 805 * 806 * @param channel the channel to close 807 * 808 * @return the {@link ChannelFuture} which will be notified on closure 809 */ 810 public static ChannelFuture close(Channel channel) { 811 ChannelFuture future = channel.getCloseFuture(); 812 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 813 channel, future, ChannelState.OPEN, Boolean.FALSE)); 814 return future; 815 } 816 817 /** 818 * Sends a {@code "close"} request to the 819 * {@link ChannelDownstreamHandler} which is placed in the closest 820 * downstream from the handler associated with the specified 821 * {@link ChannelHandlerContext}. 822 * 823 * @param ctx the context 824 * @param future the future which will be notified on closure 825 */ 826 public static void close( 827 ChannelHandlerContext ctx, ChannelFuture future) { 828 ctx.sendDownstream(new DownstreamChannelStateEvent( 829 ctx.getChannel(), future, ChannelState.OPEN, Boolean.FALSE)); 830 } 831 832 private static void validateInterestOps(int interestOps) { 833 switch (interestOps) { 834 case Channel.OP_NONE: 835 case Channel.OP_READ: 836 case Channel.OP_WRITE: 837 case Channel.OP_READ_WRITE: 838 break; 839 default: 840 throw new IllegalArgumentException( 841 "Invalid interestOps: " + interestOps); 842 } 843 } 844 845 private static int filterDownstreamInterestOps(int interestOps) { 846 return interestOps & ~Channel.OP_WRITE; 847 } 848 849 private Channels() { 850 // Unused 851 } 852 }