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.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  * @apiviz.owns org.jboss.netty.channel.group.ChannelGroupFutureListener - - notifies
111  */
112 public interface ChannelGroupFuture extends Iterable<ChannelFuture> {
113 
114     /**
115      * Returns the {@link ChannelGroup} which is associated with this future.
116      */
117     ChannelGroup getGroup();
118 
119     /**
120      * Returns the {@link ChannelFuture} of the individual I/O operation which
121      * is associated with the {@link Channel} whose ID matches the specified
122      * integer.
123      *
124      * @return the matching {@link ChannelFuture} if found.
125      *         {@code null} otherwise.
126      */
127     ChannelFuture find(Integer channelId);
128 
129     /**
130      * Returns the {@link ChannelFuture} of the individual I/O operation which
131      * is associated with the specified {@link Channel}.
132      *
133      * @return the matching {@link ChannelFuture} if found.
134      *         {@code null} otherwise.
135      */
136     ChannelFuture find(Channel channel);
137 
138     /**
139      * Returns {@code true} if and only if this future is
140      * complete, regardless of whether the operation was successful, failed,
141      * or canceled.
142      */
143     boolean isDone();
144 
145     /**
146      * Returns {@code true} if and only if all I/O operations associated with
147      * this future were successful without any failure.
148      */
149     boolean isCompleteSuccess();
150 
151     /**
152      * Returns {@code true} if and only if the I/O operations associated with
153      * this future were partially successful with some failure.
154      */
155     boolean isPartialSuccess();
156 
157     /**
158      * Returns {@code true} if and only if all I/O operations associated with
159      * this future have failed without any success.
160      */
161     boolean isCompleteFailure();
162 
163     /**
164      * Returns {@code true} if and only if the I/O operations associated with
165      * this future have failed partially with some success.
166      */
167     boolean isPartialFailure();
168 
169     /**
170      * Adds the specified listener to this future.  The
171      * specified listener is notified when this future is
172      * {@linkplain #isDone() done}.  If this future is already
173      * completed, the specified listener is notified immediately.
174      */
175     void addListener(ChannelGroupFutureListener listener);
176 
177     /**
178      * Removes the specified listener from this future.
179      * The specified listener is no longer notified when this
180      * future is {@linkplain #isDone() done}.  If this
181      * future is already completed, this method has no effect
182      * and returns silently.
183      */
184     void removeListener(ChannelGroupFutureListener listener);
185 
186     /**
187      * Waits for this future to be completed.
188      *
189      * @throws InterruptedException
190      *         if the current thread was interrupted
191      */
192     ChannelGroupFuture await() throws InterruptedException;
193 
194     /**
195      * Waits for this future to be completed without
196      * interruption.  This method catches an {@link InterruptedException} and
197      * discards it silently.
198      */
199     ChannelGroupFuture awaitUninterruptibly();
200 
201     /**
202      * Waits for this future to be completed within the
203      * specified time limit.
204      *
205      * @return {@code true} if and only if the future was completed within
206      *         the specified time limit
207      *
208      * @throws InterruptedException
209      *         if the current thread was interrupted
210      */
211     boolean await(long timeout, TimeUnit unit) throws InterruptedException;
212 
213     /**
214      * Waits for this future to be completed within the
215      * specified time limit.
216      *
217      * @return {@code true} if and only if the future was completed within
218      *         the specified time limit
219      *
220      * @throws InterruptedException
221      *         if the current thread was interrupted
222      */
223     boolean await(long timeoutMillis) throws InterruptedException;
224 
225     /**
226      * Waits for this future to be completed within the
227      * specified time limit without interruption.  This method catches an
228      * {@link InterruptedException} and discards it silently.
229      *
230      * @return {@code true} if and only if the future was completed within
231      *         the specified time limit
232      */
233     boolean awaitUninterruptibly(long timeout, TimeUnit unit);
234 
235     /**
236      * Waits for this future to be completed within the
237      * specified time limit without interruption.  This method catches an
238      * {@link InterruptedException} and discards it silently.
239      *
240      * @return {@code true} if and only if the future was completed within
241      *         the specified time limit
242      */
243     boolean awaitUninterruptibly(long timeoutMillis);
244 
245     /**
246      * Returns the {@link Iterator} that enumerates all {@link ChannelFuture}s
247      * which are associated with this future.  Please note that the returned
248      * {@link Iterator} is is unmodifiable, which means a {@link ChannelFuture}
249      * cannot be removed from this future.
250      */
251     Iterator<ChannelFuture> iterator();
252 }