View Javadoc

    1   /*
    2    * Copyright 2009 Red Hat, Inc.
    3    *
    4    * Red Hat licenses this file to you under the Apache License, version 2.0
    5    * (the "License"); you may not use this file except in compliance with the
    6    * 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.group;
    17
    18  import java.util.Iterator;
    19  import java.util.concurrent.TimeUnit;
    20
    21  import org.jboss.netty.channel.Channel;
    22  import org.jboss.netty.channel.ChannelFuture;
    23  import org.jboss.netty.channel.ChannelHandler;
    24  import org.jboss.netty.channel.ChannelHandlerContext;
    25  import org.jboss.netty.channel.ChannelPipeline;
    26  import org.jboss.netty.channel.MessageEvent;
    27  import org.jboss.netty.handler.execution.ExecutionHandler;
    28
    29  /**
    30   * The result of an asynchronous {@link ChannelGroup} operation.
    31   * {@link ChannelGroupFuture} is composed of {@link ChannelFuture}s which
    32   * represent the outcome of the individual I/O operations that affect the
    33   * {@link Channel}s in the {@link ChannelGroup}.
    34   *
    35   * <p>
    36   * All I/O operations in {@link ChannelGroup} are asynchronous.  It means any
    37   * I/O calls will return immediately with no guarantee that the requested I/O
    38   * operations have been completed at the end of the call.  Instead, you will be
    39   * returned with a {@link ChannelGroupFuture} instance which tells you when the
    40   * requested I/O operations have succeeded, failed, or cancelled.
    41   * <p>
    42   * Various methods are provided to let you check if the I/O operations has been
    43   * completed, wait for the completion, and retrieve the result of the I/O
    44   * operation. It also allows you to add more than one
    45   * {@link ChannelGroupFutureListener} so you can get notified when the I/O
    46   * operation have been completed.
    47   *
    48   * <h3>Prefer {@link #addListener(ChannelGroupFutureListener)} to {@link #await()}</h3>
    49   *
    50   * It is recommended to prefer {@link #addListener(ChannelGroupFutureListener)} to
    51   * {@link #await()} wherever possible to get notified when I/O operations are
    52   * done and to do any follow-up tasks.
    53   * <p>
    54   * {@link #addListener(ChannelGroupFutureListener)} is non-blocking.  It simply
    55   * adds the specified {@link ChannelGroupFutureListener} to the
    56   * {@link ChannelGroupFuture}, and I/O thread will notify the listeners when
    57   * the I/O operations associated with the future is done.
    58   * {@link ChannelGroupFutureListener} yields the best performance and resource
    59   * utilization because it does not block at all, but it could be tricky to
    60   * implement a sequential logic if you are not used to event-driven programming.
    61   * <p>
    62   * By contrast, {@link #await()} is a blocking operation.  Once called, the
    63   * caller thread blocks until all I/O operations are done.  It is easier to
    64   * implement a sequential logic with {@link #await()}, but the caller thread
    65   * blocks unnecessarily until all I/O operations are done and there's relatively
    66   * expensive cost of inter-thread notification.  Moreover, there's a chance of
    67   * dead lock in a particular circumstance, which is described below.
    68   *
    69   * <h3>Do not call {@link #await()} inside {@link ChannelHandler}</h3>
    70   * <p>
    71   * The event handler methods in {@link ChannelHandler} is often called by
    72   * an I/O thread unless an {@link ExecutionHandler} is in the
    73   * {@link ChannelPipeline}.  If {@link #await()} is called by an event handler
    74   * method, which is called by the I/O thread, the I/O operation it is waiting
    75   * for might never be complete because {@link #await()} can block the I/O
    76   * operation it is waiting for, which is a dead lock.
    77   * <pre>
    78   * // BAD - NEVER DO THIS
    79   * {@code @Override}
    80   * public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
    81   *     if (e.getMessage() instanceof ShutdownMessage) {
    82   *         {@link ChannelGroup} allChannels = MyServer.getAllChannels();
    83   *         {@link ChannelGroupFuture} future = allChannels.close();
    84   *         future.awaitUninterruptibly();
    85   *         // Perform post-shutdown operation
    86   *         // ...
    87   *     }
    88   * }
    89   *
    90   * // GOOD
    91   * {@code @Override}
    92   * public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
    93   *     if (e.getMessage() instanceof ShutdownMessage) {
    94   *         {@link ChannelGroup} allChannels = MyServer.getAllChannels();
    95   *         {@link ChannelGroupFuture} future = allChannels.close();
    96   *         future.addListener(new {@link ChannelGroupFutureListener}() {
    97   *             public void operationComplete({@link ChannelGroupFuture} future) {
    98   *                 // Perform post-closure operation
    99   *                 // ...
    100  *             }
    101  *         });
    102  *     }
    103  * }
    104  * </pre>
    105  * <p>
    106  * In spite of the disadvantages mentioned above, there are certainly the cases
    107  * where it is more convenient to call {@link #await()}. In such a case, please
    108  * make sure you do not call {@link #await()} in an I/O thread.  Otherwise,
    109  * {@link IllegalStateException} will be raised to prevent a dead lock.
    110  *
    111  * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
    112  * @author <a href="http://gleamynode.net/">Trustin Lee</a>
    113  * @version $Rev: 2122 $, $Date: 2010-02-02 11:00:04 +0900 (Tue, 02 Feb 2010) $
    114  *
    115  * @apiviz.owns org.jboss.netty.channel.group.ChannelGroupFutureListener - - notifies
    116  */
    117 public interface ChannelGroupFuture extends Iterable<ChannelFuture> {
    118
    119     /**
    120      * Returns the {@link ChannelGroup} which is associated with this future.
    121      */
    122     ChannelGroup getGroup();
    123
    124     /**
    125      * Returns the {@link ChannelFuture} of the individual I/O operation which
    126      * is associated with the {@link Channel} whose ID matches the specified
    127      * integer.
    128      *
    129      * @return the matching {@link ChannelFuture} if found.
    130      *         {@code null} otherwise.
    131      */
    132     ChannelFuture find(Integer channelId);
    133
    134     /**
    135      * Returns the {@link ChannelFuture} of the individual I/O operation which
    136      * is associated with the specified {@link Channel}.
    137      *
    138      * @return the matching {@link ChannelFuture} if found.
    139      *         {@code null} otherwise.
    140      */
    141     ChannelFuture find(Channel channel);
    142
    143     /**
    144      * Returns {@code true} if and only if this future is
    145      * complete, regardless of whether the operation was successful, failed,
    146      * or canceled.
    147      */
    148     boolean isDone();
    149
    150     /**
    151      * Returns {@code true} if and only if all I/O operations associated with
    152      * this future were successful without any failure.
    153      */
    154     boolean isCompleteSuccess();
    155
    156     /**
    157      * Returns {@code true} if and only if the I/O operations associated with
    158      * this future were partially successful with some failure.
    159      */
    160     boolean isPartialSuccess();
    161
    162     /**
    163      * Returns {@code true} if and only if all I/O operations associated with
    164      * this future have failed without any success.
    165      */
    166     boolean isCompleteFailure();
    167
    168     /**
    169      * Returns {@code true} if and only if the I/O operations associated with
    170      * this future have failed partially with some success.
    171      */
    172     boolean isPartialFailure();
    173
    174     /**
    175      * Adds the specified listener to this future.  The
    176      * specified listener is notified when this future is
    177      * {@linkplain #isDone() done}.  If this future is already
    178      * completed, the specified listener is notified immediately.
    179      */
    180     void addListener(ChannelGroupFutureListener listener);
    181
    182     /**
    183      * Removes the specified listener from this future.
    184      * The specified listener is no longer notified when this
    185      * future is {@linkplain #isDone() done}.  If this
    186      * future is already completed, this method has no effect
    187      * and returns silently.
    188      */
    189     void removeListener(ChannelGroupFutureListener listener);
    190
    191     /**
    192      * Waits for this future to be completed.
    193      *
    194      * @throws InterruptedException
    195      *         if the current thread was interrupted
    196      */
    197     ChannelGroupFuture await() throws InterruptedException;
    198
    199     /**
    200      * Waits for this future to be completed without
    201      * interruption.  This method catches an {@link InterruptedException} and
    202      * discards it silently.
    203      */
    204     ChannelGroupFuture awaitUninterruptibly();
    205
    206     /**
    207      * Waits for this future to be completed within the
    208      * specified time limit.
    209      *
    210      * @return {@code true} if and only if the future was completed within
    211      *         the specified time limit
    212      *
    213      * @throws InterruptedException
    214      *         if the current thread was interrupted
    215      */
    216     boolean await(long timeout, TimeUnit unit) throws InterruptedException;
    217
    218     /**
    219      * Waits for this future to be completed within the
    220      * specified time limit.
    221      *
    222      * @return {@code true} if and only if the future was completed within
    223      *         the specified time limit
    224      *
    225      * @throws InterruptedException
    226      *         if the current thread was interrupted
    227      */
    228     boolean await(long timeoutMillis) throws InterruptedException;
    229
    230     /**
    231      * Waits for this future to be completed within the
    232      * specified time limit without interruption.  This method catches an
    233      * {@link InterruptedException} and discards it silently.
    234      *
    235      * @return {@code true} if and only if the future was completed within
    236      *         the specified time limit
    237      */
    238     boolean awaitUninterruptibly(long timeout, TimeUnit unit);
    239
    240     /**
    241      * Waits for this future to be completed within the
    242      * specified time limit without interruption.  This method catches an
    243      * {@link InterruptedException} and discards it silently.
    244      *
    245      * @return {@code true} if and only if the future was completed within
    246      *         the specified time limit
    247      */
    248     boolean awaitUninterruptibly(long timeoutMillis);
    249
    250     /**
    251      * Returns the {@link Iterator} that enumerates all {@link ChannelFuture}s
    252      * which are associated with this future.  Please note that the returned
    253      * {@link Iterator} is is unmodifiable, which means a {@link ChannelFuture}
    254      * cannot be removed from this future.
    255      */
    256     Iterator<ChannelFuture> iterator();
    257 }