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 316 /** 317 * Sends a {@code "writeComplete"} event to the first 318 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 319 * the specified {@link Channel}. 320 */ 321 public static void fireWriteComplete(Channel channel, long amount) { 322 if (amount == 0) { 323 return; 324 } 325 326 channel.getPipeline().sendUpstream( 327 new DefaultWriteCompletionEvent(channel, amount)); 328 } 329 330 /** 331 * Sends a {@code "writeComplete"} event to the 332 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 333 * from the handler associated with the specified 334 * {@link ChannelHandlerContext}. 335 */ 336 public static void fireWriteComplete(ChannelHandlerContext ctx, long amount) { 337 ctx.sendUpstream(new DefaultWriteCompletionEvent(ctx.getChannel(), amount)); 338 } 339 340 /** 341 * Sends a {@code "channelInterestChanged"} event to the first 342 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 343 * the specified {@link Channel} once the io-thread runs again. 344 */ 345 public static ChannelFuture fireChannelInterestChangedLater(final Channel channel) { 346 return channel.getPipeline().execute(new Runnable() { 347 348 public void run() { 349 fireChannelInterestChanged(channel); 350 351 } 352 }); 353 } 354 355 /** 356 * Sends a {@code "channelInterestChanged"} event to the first 357 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 358 * the specified {@link Channel}. 359 */ 360 public static void fireChannelInterestChanged(Channel channel) { 361 channel.getPipeline().sendUpstream( 362 new UpstreamChannelStateEvent( 363 channel, ChannelState.INTEREST_OPS, Channel.OP_READ)); 364 } 365 366 /** 367 * Sends a {@code "channelInterestChanged"} event to the 368 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 369 * from the handler associated with the specified 370 * {@link ChannelHandlerContext}. 371 */ 372 public static void fireChannelInterestChanged( 373 ChannelHandlerContext ctx) { 374 375 ctx.sendUpstream( 376 new UpstreamChannelStateEvent( 377 ctx.getChannel(), ChannelState.INTEREST_OPS, Channel.OP_READ)); 378 } 379 380 /** 381 * Sends a {@code "channelDisconnected"} event to the first 382 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 383 * the specified {@link Channel} once the io-thread runs again. 384 */ 385 public static ChannelFuture fireChannelDisconnectedLater(final Channel channel) { 386 return channel.getPipeline().execute(new Runnable() { 387 388 public void run() { 389 fireChannelDisconnected(channel); 390 } 391 }); 392 } 393 /** 394 * Sends a {@code "channelDisconnected"} event to the first 395 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 396 * the specified {@link Channel}. 397 */ 398 public static void fireChannelDisconnected(Channel channel) { 399 channel.getPipeline().sendUpstream( 400 new UpstreamChannelStateEvent( 401 channel, ChannelState.CONNECTED, null)); 402 } 403 404 /** 405 * Sends a {@code "channelDisconnected"} event to the 406 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 407 * from the handler associated with the specified 408 * {@link ChannelHandlerContext}. 409 */ 410 public static void fireChannelDisconnected(ChannelHandlerContext ctx) { 411 ctx.sendUpstream(new UpstreamChannelStateEvent( 412 ctx.getChannel(), ChannelState.CONNECTED, null)); 413 } 414 415 /** 416 * Sends a {@code "channelUnbound"} event to the first 417 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 418 * the specified {@link Channel} once the io-thread runs again. 419 */ 420 public static ChannelFuture fireChannelUnboundLater(final Channel channel) { 421 return channel.getPipeline().execute(new Runnable() { 422 423 public void run() { 424 fireChannelUnbound(channel); 425 } 426 }); 427 } 428 429 430 /** 431 * Sends a {@code "channelUnbound"} event to the first 432 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 433 * the specified {@link Channel}. 434 */ 435 public static void fireChannelUnbound(Channel channel) { 436 channel.getPipeline().sendUpstream(new UpstreamChannelStateEvent( 437 channel, ChannelState.BOUND, null)); 438 } 439 440 /** 441 * Sends a {@code "channelUnbound"} event to the 442 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 443 * from the handler associated with the specified 444 * {@link ChannelHandlerContext}. 445 */ 446 public static void fireChannelUnbound(ChannelHandlerContext ctx) { 447 448 ctx.sendUpstream(new UpstreamChannelStateEvent( 449 ctx.getChannel(), ChannelState.BOUND, null)); 450 } 451 452 453 454 /** 455 * Sends a {@code "channelClosed"} event to the first 456 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 457 * the specified {@link Channel} once the io-thread runs again. 458 */ 459 public static ChannelFuture fireChannelClosedLater(final Channel channel) { 460 return channel.getPipeline().execute(new Runnable() { 461 462 public void run() { 463 fireChannelClosed(channel); 464 } 465 }); 466 467 } 468 469 470 /** 471 * Sends a {@code "channelClosed"} event to the first 472 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 473 * the specified {@link Channel}. 474 */ 475 public static void fireChannelClosed(Channel channel) { 476 channel.getPipeline().sendUpstream( 477 new UpstreamChannelStateEvent( 478 channel, ChannelState.OPEN, Boolean.FALSE)); 479 480 // Notify the parent handler. 481 if (channel.getParent() != null) { 482 fireChildChannelStateChanged(channel.getParent(), channel); 483 } 484 } 485 486 /** 487 * Sends a {@code "channelClosed"} event to the 488 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 489 * from the handler associated with the specified 490 * {@link ChannelHandlerContext}. 491 */ 492 public static void fireChannelClosed(ChannelHandlerContext ctx) { 493 ctx.sendUpstream( 494 new UpstreamChannelStateEvent( 495 ctx.getChannel(), ChannelState.OPEN, Boolean.FALSE)); 496 } 497 498 /** 499 * Sends a {@code "exceptionCaught"} event to the first 500 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 501 * the specified {@link Channel} once the io-thread runs again. 502 */ 503 public static ChannelFuture fireExceptionCaughtLater(final Channel channel, final Throwable cause) { 504 return channel.getPipeline().execute(new Runnable() { 505 506 public void run() { 507 fireExceptionCaught(channel, cause); 508 } 509 }); 510 } 511 512 /** 513 * Sends a {@code "exceptionCaught"} event to the 514 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 515 * from the handler associated with the specified 516 * {@link ChannelHandlerContext} once the io-thread runs again. 517 */ 518 public static ChannelFuture fireExceptionCaughtLater(final ChannelHandlerContext ctx, final Throwable cause) { 519 return ctx.getPipeline().execute(new Runnable() { 520 521 public void run() { 522 fireExceptionCaught(ctx, cause); 523 } 524 }); 525 } 526 527 /** 528 * Sends a {@code "exceptionCaught"} event to the first 529 * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of 530 * the specified {@link Channel}. 531 */ 532 public static void fireExceptionCaught(Channel channel, Throwable cause) { 533 channel.getPipeline().sendUpstream( 534 new DefaultExceptionEvent(channel, cause)); 535 } 536 537 /** 538 * Sends a {@code "exceptionCaught"} event to the 539 * {@link ChannelUpstreamHandler} which is placed in the closest upstream 540 * from the handler associated with the specified 541 * {@link ChannelHandlerContext}. 542 */ 543 public static void fireExceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 544 ctx.sendUpstream(new DefaultExceptionEvent(ctx.getChannel(), cause)); 545 } 546 547 private static void fireChildChannelStateChanged( 548 Channel channel, Channel childChannel) { 549 channel.getPipeline().sendUpstream( 550 new DefaultChildChannelStateEvent(channel, childChannel)); 551 } 552 553 /** 554 * Sends a {@code "bind"} request to the last 555 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 556 * the specified {@link Channel}. 557 * 558 * @param channel the channel to bind 559 * @param localAddress the local address to bind to 560 * 561 * @return the {@link ChannelFuture} which will be notified when the 562 * bind operation is done 563 */ 564 public static ChannelFuture bind(Channel channel, SocketAddress localAddress) { 565 if (localAddress == null) { 566 throw new NullPointerException("localAddress"); 567 } 568 ChannelFuture future = future(channel); 569 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 570 channel, future, ChannelState.BOUND, localAddress)); 571 return future; 572 } 573 574 /** 575 * Sends a {@code "bind"} request to the 576 * {@link ChannelDownstreamHandler} which is placed in the closest 577 * downstream from the handler associated with the specified 578 * {@link ChannelHandlerContext}. 579 * 580 * @param ctx the context 581 * @param future the future which will be notified when the bind 582 * operation is done 583 * @param localAddress the local address to bind to 584 */ 585 public static void bind( 586 ChannelHandlerContext ctx, ChannelFuture future, SocketAddress localAddress) { 587 if (localAddress == null) { 588 throw new NullPointerException("localAddress"); 589 } 590 ctx.sendDownstream(new DownstreamChannelStateEvent( 591 ctx.getChannel(), future, ChannelState.BOUND, localAddress)); 592 } 593 594 /** 595 * Sends a {@code "unbind"} request to the 596 * {@link ChannelDownstreamHandler} which is placed in the closest 597 * downstream from the handler associated with the specified 598 * {@link ChannelHandlerContext}. 599 * 600 * @param ctx the context 601 * @param future the future which will be notified when the unbind 602 * operation is done 603 */ 604 public static void unbind(ChannelHandlerContext ctx, ChannelFuture future) { 605 ctx.sendDownstream(new DownstreamChannelStateEvent( 606 ctx.getChannel(), future, ChannelState.BOUND, null)); 607 } 608 609 /** 610 * Sends a {@code "unbind"} request to the last 611 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 612 * the specified {@link Channel}. 613 * 614 * @param channel the channel to unbind 615 * 616 * @return the {@link ChannelFuture} which will be notified when the 617 * unbind operation is done 618 */ 619 public static ChannelFuture unbind(Channel channel) { 620 ChannelFuture future = future(channel); 621 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 622 channel, future, ChannelState.BOUND, null)); 623 return future; 624 } 625 626 /** 627 * Sends a {@code "connect"} request to the last 628 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 629 * the specified {@link Channel}. 630 * 631 * @param channel the channel to attempt a connection 632 * @param remoteAddress the remote address to connect to 633 * 634 * @return the {@link ChannelFuture} which will be notified when the 635 * connection attempt is done 636 */ 637 public static ChannelFuture connect(Channel channel, SocketAddress remoteAddress) { 638 if (remoteAddress == null) { 639 throw new NullPointerException("remoteAddress"); 640 } 641 ChannelFuture future = future(channel, true); 642 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 643 channel, future, ChannelState.CONNECTED, remoteAddress)); 644 return future; 645 } 646 647 /** 648 * Sends a {@code "connect"} request to the 649 * {@link ChannelDownstreamHandler} which is placed in the closest 650 * downstream from the handler associated with the specified 651 * {@link ChannelHandlerContext}. 652 * 653 * @param ctx the context 654 * @param future the future which will be notified when the connection 655 * attempt is done 656 * @param remoteAddress the remote address to connect to 657 */ 658 public static void connect( 659 ChannelHandlerContext ctx, ChannelFuture future, SocketAddress remoteAddress) { 660 if (remoteAddress == null) { 661 throw new NullPointerException("remoteAddress"); 662 } 663 ctx.sendDownstream(new DownstreamChannelStateEvent( 664 ctx.getChannel(), future, ChannelState.CONNECTED, remoteAddress)); 665 } 666 667 /** 668 * Sends a {@code "write"} request to the last 669 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 670 * the specified {@link Channel}. 671 * 672 * @param channel the channel to write a message 673 * @param message the message to write to the channel 674 * 675 * @return the {@link ChannelFuture} which will be notified when the 676 * write operation is done 677 */ 678 public static ChannelFuture write(Channel channel, Object message) { 679 return write(channel, message, null); 680 } 681 682 /** 683 * Sends a {@code "write"} request to the 684 * {@link ChannelDownstreamHandler} which is placed in the closest 685 * downstream from the handler associated with the specified 686 * {@link ChannelHandlerContext}. 687 * 688 * @param ctx the context 689 * @param future the future which will be notified when the write 690 * operation is done 691 */ 692 public static void write( 693 ChannelHandlerContext ctx, ChannelFuture future, Object message) { 694 write(ctx, future, message, null); 695 } 696 697 /** 698 * Sends a {@code "write"} request to the last 699 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 700 * the specified {@link Channel}. 701 * 702 * @param channel the channel to write a message 703 * @param message the message to write to the channel 704 * @param remoteAddress the destination of the message. 705 * {@code null} to use the default remote address 706 * 707 * @return the {@link ChannelFuture} which will be notified when the 708 * write operation is done 709 */ 710 public static ChannelFuture write(Channel channel, Object message, SocketAddress remoteAddress) { 711 ChannelFuture future = future(channel); 712 channel.getPipeline().sendDownstream( 713 new DownstreamMessageEvent(channel, future, message, remoteAddress)); 714 return future; 715 } 716 717 /** 718 * Sends a {@code "write"} request to the 719 * {@link ChannelDownstreamHandler} which is placed in the closest 720 * downstream from the handler associated with the specified 721 * {@link ChannelHandlerContext}. 722 * 723 * @param ctx the context 724 * @param future the future which will be notified when the write 725 * operation is done 726 * @param message the message to write to the channel 727 * @param remoteAddress the destination of the message. 728 * {@code null} to use the default remote address. 729 */ 730 public static void write( 731 ChannelHandlerContext ctx, ChannelFuture future, 732 Object message, SocketAddress remoteAddress) { 733 ctx.sendDownstream( 734 new DownstreamMessageEvent(ctx.getChannel(), future, message, remoteAddress)); 735 } 736 737 /** 738 * Sends a {@code "setInterestOps"} request to the last 739 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 740 * the specified {@link Channel}. 741 * 742 * @param channel the channel to change its interestOps 743 * @param interestOps the new interestOps 744 * 745 * @return the {@link ChannelFuture} which will be notified when the 746 * interestOps is changed 747 */ 748 public static ChannelFuture setInterestOps(Channel channel, int interestOps) { 749 validateInterestOps(interestOps); 750 interestOps = filterDownstreamInterestOps(interestOps); 751 752 ChannelFuture future = future(channel); 753 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 754 channel, future, ChannelState.INTEREST_OPS, interestOps)); 755 return future; 756 } 757 758 /** 759 * Sends a {@code "setInterestOps"} request to the 760 * {@link ChannelDownstreamHandler} which is placed in the closest 761 * downstream from the handler associated with the specified 762 * {@link ChannelHandlerContext}. 763 * 764 * @param ctx the context 765 * @param future the future which will be notified when the interestOps is 766 * changed. 767 */ 768 public static void setInterestOps( 769 ChannelHandlerContext ctx, ChannelFuture future, int interestOps) { 770 validateInterestOps(interestOps); 771 interestOps = filterDownstreamInterestOps(interestOps); 772 773 ctx.sendDownstream( 774 new DownstreamChannelStateEvent( 775 ctx.getChannel(), future, ChannelState.INTEREST_OPS, interestOps)); 776 } 777 778 /** 779 * Sends a {@code "disconnect"} request to the last 780 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 781 * the specified {@link Channel}. 782 * 783 * @param channel the channel to disconnect 784 * 785 * @return the {@link ChannelFuture} which will be notified on disconnection 786 */ 787 public static ChannelFuture disconnect(Channel channel) { 788 ChannelFuture future = future(channel); 789 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 790 channel, future, ChannelState.CONNECTED, null)); 791 return future; 792 } 793 794 /** 795 * Sends a {@code "disconnect"} request to the 796 * {@link ChannelDownstreamHandler} which is placed in the closest 797 * downstream from the handler associated with the specified 798 * {@link ChannelHandlerContext}. 799 * 800 * @param ctx the context 801 * @param future the future which will be notified on disconnection 802 */ 803 public static void disconnect( 804 ChannelHandlerContext ctx, ChannelFuture future) { 805 ctx.sendDownstream(new DownstreamChannelStateEvent( 806 ctx.getChannel(), future, ChannelState.CONNECTED, null)); 807 } 808 809 /** 810 * Sends a {@code "close"} request to the last 811 * {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of 812 * the specified {@link Channel}. 813 * 814 * @param channel the channel to close 815 * 816 * @return the {@link ChannelFuture} which will be notified on closure 817 */ 818 public static ChannelFuture close(Channel channel) { 819 ChannelFuture future = channel.getCloseFuture(); 820 channel.getPipeline().sendDownstream(new DownstreamChannelStateEvent( 821 channel, future, ChannelState.OPEN, Boolean.FALSE)); 822 return future; 823 } 824 825 /** 826 * Sends a {@code "close"} request to the 827 * {@link ChannelDownstreamHandler} which is placed in the closest 828 * downstream from the handler associated with the specified 829 * {@link ChannelHandlerContext}. 830 * 831 * @param ctx the context 832 * @param future the future which will be notified on closure 833 */ 834 public static void close( 835 ChannelHandlerContext ctx, ChannelFuture future) { 836 ctx.sendDownstream(new DownstreamChannelStateEvent( 837 ctx.getChannel(), future, ChannelState.OPEN, Boolean.FALSE)); 838 } 839 840 private static void validateInterestOps(int interestOps) { 841 switch (interestOps) { 842 case Channel.OP_NONE: 843 case Channel.OP_READ: 844 case Channel.OP_WRITE: 845 case Channel.OP_READ_WRITE: 846 break; 847 default: 848 throw new IllegalArgumentException( 849 "Invalid interestOps: " + interestOps); 850 } 851 } 852 853 private static int filterDownstreamInterestOps(int interestOps) { 854 return interestOps & ~Channel.OP_WRITE; 855 } 856 857 private Channels() { 858 // Unused 859 } 860 }