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 }