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.util.concurrent.TimeUnit;
    19
    20  import org.jboss.netty.bootstrap.ClientBootstrap;
    21  import org.jboss.netty.handler.execution.ExecutionHandler;
    22
    23  /**
    24   * The result of an asynchronous {@link Channel} I/O operation.
    25   * <p>
    26   * All I/O operations in Netty are asynchronous.  It means any I/O calls will
    27   * return immediately with no guarantee that the requested I/O operation has
    28   * been completed at the end of the call.  Instead, you will be returned with
    29   * a {@link ChannelFuture} instance which gives you the information about the
    30   * result or status of the I/O operation.
    31   * <p>
    32   * A {@link ChannelFuture} is either <em>uncompleted</em> or <em>completed</em>.
    33   * When an I/O operation begins, a new future object is created.  The new future
    34   * is uncompleted initially - it is neither succeeded, failed, nor cancelled
    35   * because the I/O operation is not finished yet.  If the I/O operation is
    36   * finished either successfully, with failure, or by cancellation, the future is
    37   * marked as completed with more specific information, such as the cause of the
    38   * failure.  Please note that even failure and cancellation belong to the
    39   * completed state.
    40   * <pre>
    41   *                                      +---------------------------+
    42   *                                      | Completed successfully    |
    43   *                                      +---------------------------+
    44   *                                 +---->      isDone() = <b>true</b>      |
    45   * +--------------------------+    |    |   isSuccess() = <b>true</b>      |
    46   * |        Uncompleted       |    |    +===========================+
    47   * +--------------------------+    |    | Completed with failure    |
    48   * |      isDone() = <b>false</b>    |    |    +---------------------------+
    49   * |   isSuccess() = false    |----+---->   isDone() = <b>true</b>         |
    50   * | isCancelled() = false    |    |    | getCause() = <b>non-null</b>     |
    51   * |    getCause() = null     |    |    +===========================+
    52   * +--------------------------+    |    | Completed by cancellation |
    53   *                                 |    +---------------------------+
    54   *                                 +---->      isDone() = <b>true</b>      |
    55   *                                      | isCancelled() = <b>true</b>      |
    56   *                                      +---------------------------+
    57   * </pre>
    58   *
    59   * Various methods are provided to let you check if the I/O operation has been
    60   * completed, wait for the completion, and retrieve the result of the I/O
    61   * operation. It also allows you to add {@link ChannelFutureListener}s so you
    62   * can get notified when the I/O operation is completed.
    63   *
    64   * <h3>Prefer {@link #addListener(ChannelFutureListener)} to {@link #await()}</h3>
    65   *
    66   * It is recommended to prefer {@link #addListener(ChannelFutureListener)} to
    67   * {@link #await()} wherever possible to get notified when an I/O operation is
    68   * done and to do any follow-up tasks.
    69   * <p>
    70   * {@link #addListener(ChannelFutureListener)} is non-blocking.  It simply adds
    71   * the specified {@link ChannelFutureListener} to the {@link ChannelFuture}, and
    72   * I/O thread will notify the listeners when the I/O operation associated with
    73   * the future is done.  {@link ChannelFutureListener} yields the best
    74   * performance and resource utilization because it does not block at all, but
    75   * it could be tricky to implement a sequential logic if you are not used to
    76   * event-driven programming.
    77   * <p>
    78   * By contrast, {@link #await()} is a blocking operation.  Once called, the
    79   * caller thread blocks until the operation is done.  It is easier to implement
    80   * a sequential logic with {@link #await()}, but the caller thread blocks
    81   * unnecessarily until the I/O operation is done and there's relatively
    82   * expensive cost of inter-thread notification.  Moreover, there's a chance of
    83   * dead lock in a particular circumstance, which is described below.
    84   *
    85   * <h3>Do not call {@link #await()} inside {@link ChannelHandler}</h3>
    86   * <p>
    87   * The event handler methods in {@link ChannelHandler} is often called by
    88   * an I/O thread unless an {@link ExecutionHandler} is in the
    89   * {@link ChannelPipeline}.  If {@link #await()} is called by an event handler
    90   * method, which is called by the I/O thread, the I/O operation it is waiting
    91   * for might never be complete because {@link #await()} can block the I/O
    92   * operation it is waiting for, which is a dead lock.
    93   * <pre>
    94   * // BAD - NEVER DO THIS
    95   * {@code @Override}
    96   * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
    97   *     if (e.getMessage() instanceof GoodByeMessage) {
    98   *         {@link ChannelFuture} future = e.getChannel().close();
    99   *         future.awaitUninterruptibly();
    100  *         // Perform post-closure operation
    101  *         // ...
    102  *     }
    103  * }
    104  *
    105  * // GOOD
    106  * {@code @Override}
    107  * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
    108  *     if (e.getMessage() instanceof GoodByeMessage) {
    109  *         {@link ChannelFuture} future = e.getChannel().close();
    110  *         future.addListener(new {@link ChannelFutureListener}() {
    111  *             public void operationComplete({@link ChannelFuture} future) {
    112  *                 // Perform post-closure operation
    113  *                 // ...
    114  *             }
    115  *         });
    116  *     }
    117  * }
    118  * </pre>
    119  * <p>
    120  * In spite of the disadvantages mentioned above, there are certainly the cases
    121  * where it is more convenient to call {@link #await()}. In such a case, please
    122  * make sure you do not call {@link #await()} in an I/O thread.  Otherwise,
    123  * {@link IllegalStateException} will be raised to prevent a dead lock.
    124  *
    125  * <h3>Do not confuse I/O timeout and await timeout</h3>
    126  *
    127  * The timeout value you specify with {@link #await(long)},
    128  * {@link #await(long, TimeUnit)}, {@link #awaitUninterruptibly(long)}, or
    129  * {@link #awaitUninterruptibly(long, TimeUnit)} are not related with I/O
    130  * timeout at all.  If an I/O operation times out, the future will be marked as
    131  * 'completed with failure,' as depicted in the diagram above.  For example,
    132  * connect timeout should be configured via a transport-specific option:
    133  * <pre>
    134  * // BAD - NEVER DO THIS
    135  * {@link ClientBootstrap} b = ...;
    136  * {@link ChannelFuture} f = b.connect(...);
    137  * f.awaitUninterruptibly(10, TimeUnit.SECONDS);
    138  * if (f.isCancelled()) {
    139  *     // Connection attempt cancelled by user
    140  * } else if (!f.isSuccess()) {
    141  *     // You might get a NullPointerException here because the future
    142  *     // might not be completed yet.
    143  *     f.getCause().printStackTrace();
    144  * } else {
    145  *     // Connection established successfully
    146  * }
    147  *
    148  * // GOOD
    149  * {@link ClientBootstrap} b = ...;
    150  * // Configure the connect timeout option.
    151  * <b>b.setOption("connectTimeoutMillis", 10000);</b>
    152  * {@link ChannelFuture} f = b.connect(...);
    153  * f.awaitUninterruptibly();
    154  *
    155  * // Now we are sure the future is completed.
    156  * assert f.isDone();
    157  *
    158  * if (f.isCancelled()) {
    159  *     // Connection attempt cancelled by user
    160  * } else if (!f.isSuccess()) {
    161  *     f.getCause().printStackTrace();
    162  * } else {
    163  *     // Connection established successfully
    164  * }
    165  * </pre>
    166  *
    167  * @apiviz.landmark
    168  * @apiviz.owns org.jboss.netty.channel.ChannelFutureListener - - notifies
    169  */
    170 public interface ChannelFuture {
    171
    172     /**
    173      * Returns a channel where the I/O operation associated with this
    174      * future takes place.
    175      */
    176     Channel getChannel();
    177
    178     /**
    179      * Returns {@code true} if and only if this future is
    180      * complete, regardless of whether the operation was successful, failed,
    181      * or cancelled.
    182      */
    183     boolean isDone();
    184
    185     /**
    186      * Returns {@code true} if and only if this future was
    187      * cancelled by a {@link #cancel()} method.
    188      */
    189     boolean isCancelled();
    190
    191     /**
    192      * Returns {@code true} if and only if the I/O operation was completed
    193      * successfully.
    194      */
    195     boolean isSuccess();
    196
    197     /**
    198      * Returns the cause of the failed I/O operation if the I/O operation has
    199      * failed.
    200      *
    201      * @return the cause of the failure.
    202      *         {@code null} if succeeded or this future is not
    203      *         completed yet.
    204      */
    205     Throwable getCause();
    206
    207     /**
    208      * Cancels the I/O operation associated with this future
    209      * and notifies all listeners if canceled successfully.
    210      *
    211      * @return {@code true} if and only if the operation has been canceled.
    212      *         {@code false} if the operation can't be canceled or is already
    213      *         completed.
    214      */
    215     boolean cancel();
    216
    217     /**
    218      * Marks this future as a success and notifies all
    219      * listeners.
    220      *
    221      * @return {@code true} if and only if successfully marked this future as
    222      *         a success. Otherwise {@code false} because this future is
    223      *         already marked as either a success or a failure.
    224      */
    225     boolean setSuccess();
    226
    227     /**
    228      * Marks this future as a failure and notifies all
    229      * listeners.
    230      *
    231      * @return {@code true} if and only if successfully marked this future as
    232      *         a failure. Otherwise {@code false} because this future is
    233      *         already marked as either a success or a failure.
    234      */
    235     boolean setFailure(Throwable cause);
    236
    237     /**
    238      * Notifies the progress of the operation to the listeners that implements
    239      * {@link ChannelFutureProgressListener}. Please note that this method will
    240      * not do anything and return {@code false} if this future is complete
    241      * already.
    242      *
    243      * @return {@code true} if and only if notification was made.
    244      */
    245     boolean setProgress(long amount, long current, long total);
    246
    247     /**
    248      * Adds the specified listener to this future.  The
    249      * specified listener is notified when this future is
    250      * {@linkplain #isDone() done}.  If this future is already
    251      * completed, the specified listener is notified immediately.
    252      */
    253     void addListener(ChannelFutureListener listener);
    254
    255     /**
    256      * Removes the specified listener from this future.
    257      * The specified listener is no longer notified when this
    258      * future is {@linkplain #isDone() done}.  If the specified
    259      * listener is not associated with this future, this method
    260      * does nothing and returns silently.
    261      */
    262     void removeListener(ChannelFutureListener listener);
    263
    264     /**
    265      * @deprecated Use {@link #sync()} or {@link #syncUninterruptibly()} instead.
    266      */
    267     @Deprecated
    268     ChannelFuture rethrowIfFailed() throws Exception;
    269
    270     /**
    271      * Waits for this future until it is done, and rethrows the cause of the failure if this future
    272      * failed.  If the cause of the failure is a checked exception, it is wrapped with a new
    273      * {@link ChannelException} before being thrown.
    274      */
    275     ChannelFuture sync() throws InterruptedException;
    276
    277     /**
    278      * Waits for this future until it is done, and rethrows the cause of the failure if this future
    279      * failed.  If the cause of the failure is a checked exception, it is wrapped with a new
    280      * {@link ChannelException} before being thrown.
    281      */
    282     ChannelFuture syncUninterruptibly();
    283
    284     /**
    285      * Waits for this future to be completed.
    286      *
    287      * @throws InterruptedException
    288      *         if the current thread was interrupted
    289      */
    290     ChannelFuture await() throws InterruptedException;
    291
    292     /**
    293      * Waits for this future to be completed without
    294      * interruption.  This method catches an {@link InterruptedException} and
    295      * discards it silently.
    296      */
    297     ChannelFuture awaitUninterruptibly();
    298
    299     /**
    300      * Waits for this future to be completed within the
    301      * specified time limit.
    302      *
    303      * @return {@code true} if and only if the future was completed within
    304      *         the specified time limit
    305      *
    306      * @throws InterruptedException
    307      *         if the current thread was interrupted
    308      */
    309     boolean await(long timeout, TimeUnit unit) throws InterruptedException;
    310
    311     /**
    312      * Waits for this future to be completed within the
    313      * specified time limit.
    314      *
    315      * @return {@code true} if and only if the future was completed within
    316      *         the specified time limit
    317      *
    318      * @throws InterruptedException
    319      *         if the current thread was interrupted
    320      */
    321     boolean await(long timeoutMillis) throws InterruptedException;
    322
    323     /**
    324      * Waits for this future to be completed within the
    325      * specified time limit without interruption.  This method catches an
    326      * {@link InterruptedException} and discards it silently.
    327      *
    328      * @return {@code true} if and only if the future was completed within
    329      *         the specified time limit
    330      */
    331     boolean awaitUninterruptibly(long timeout, TimeUnit unit);
    332
    333     /**
    334      * Waits for this future to be completed within the
    335      * specified time limit without interruption.  This method catches an
    336      * {@link InterruptedException} and discards it silently.
    337      *
    338      * @return {@code true} if and only if the future was completed within
    339      *         the specified time limit
    340      */
    341     boolean awaitUninterruptibly(long timeoutMillis);
    342 }