View Javadoc

    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 }