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 }