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 * https://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 io.netty.channel.group;
17
18 import io.netty.channel.Channel;
19 import io.netty.channel.ChannelFuture;
20 import io.netty.channel.ChannelHandler;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.util.concurrent.Future;
23 import io.netty.util.concurrent.GenericFutureListener;
24
25 import java.util.Iterator;
26
27 /**
28 * The result of an asynchronous {@link ChannelGroup} operation.
29 * {@link ChannelGroupFuture} is composed of {@link ChannelFuture}s which
30 * represent the outcome of the individual I/O operations that affect the
31 * {@link Channel}s in the {@link ChannelGroup}.
32 *
33 * <p>
34 * All I/O operations in {@link ChannelGroup} are asynchronous. It means any
35 * I/O calls will return immediately with no guarantee that the requested I/O
36 * operations have been completed at the end of the call. Instead, you will be
37 * returned with a {@link ChannelGroupFuture} instance which tells you when the
38 * requested I/O operations have succeeded, failed, or cancelled.
39 * <p>
40 * Various methods are provided to let you check if the I/O operations has been
41 * completed, wait for the completion, and retrieve the result of the I/O
42 * operation. It also allows you to add more than one
43 * {@link ChannelGroupFutureListener} so you can get notified when the I/O
44 * operation have been completed.
45 *
46 * <h3>Prefer {@link #addListener(GenericFutureListener)} to {@link #await()}</h3>
47 *
48 * It is recommended to prefer {@link #addListener(GenericFutureListener)} to
49 * {@link #await()} wherever possible to get notified when I/O operations are
50 * done and to do any follow-up tasks.
51 * <p>
52 * {@link #addListener(GenericFutureListener)} is non-blocking. It simply
53 * adds the specified {@link ChannelGroupFutureListener} to the
54 * {@link ChannelGroupFuture}, and I/O thread will notify the listeners when
55 * the I/O operations associated with the future is done.
56 * {@link ChannelGroupFutureListener} yields the best performance and resource
57 * utilization because it does not block at all, but it could be tricky to
58 * implement a sequential logic if you are not used to event-driven programming.
59 * <p>
60 * By contrast, {@link #await()} is a blocking operation. Once called, the
61 * caller thread blocks until all I/O operations are done. It is easier to
62 * implement a sequential logic with {@link #await()}, but the caller thread
63 * blocks unnecessarily until all I/O operations are done and there's relatively
64 * expensive cost of inter-thread notification. Moreover, there's a chance of
65 * dead lock in a particular circumstance, which is described below.
66 *
67 * <h3>Do not call {@link #await()} inside {@link ChannelHandler}</h3>
68 * <p>
69 * The event handler methods in {@link ChannelHandler} is often called by
70 * an I/O thread. If {@link #await()} is called by an event handler
71 * method, which is called by the I/O thread, the I/O operation it is waiting
72 * for might never be complete because {@link #await()} can block the I/O
73 * operation it is waiting for, which is a dead lock.
74 * <pre>
75 * // BAD - NEVER DO THIS
76 * {@code @Override}
77 * public void messageReceived({@link ChannelHandlerContext} ctx, ShutdownMessage msg) {
78 * {@link ChannelGroup} allChannels = MyServer.getAllChannels();
79 * {@link ChannelGroupFuture} future = allChannels.close();
80 * future.awaitUninterruptibly();
81 * // Perform post-shutdown operation
82 * // ...
83 *
84 * }
85 *
86 * // GOOD
87 * {@code @Override}
88 * public void messageReceived(ChannelHandlerContext ctx, ShutdownMessage msg) {
89 * {@link ChannelGroup} allChannels = MyServer.getAllChannels();
90 * {@link ChannelGroupFuture} future = allChannels.close();
91 * future.addListener(new {@link ChannelGroupFutureListener}() {
92 * public void operationComplete({@link ChannelGroupFuture} future) {
93 * // Perform post-closure operation
94 * // ...
95 * }
96 * });
97 * }
98 * </pre>
99 * <p>
100 * In spite of the disadvantages mentioned above, there are certainly the cases
101 * where it is more convenient to call {@link #await()}. In such a case, please
102 * make sure you do not call {@link #await()} in an I/O thread. Otherwise,
103 * {@link IllegalStateException} will be raised to prevent a dead lock.
104 */
105 public interface ChannelGroupFuture extends Future<Void>, Iterable<ChannelFuture> {
106
107 /**
108 * Returns the {@link ChannelGroup} which is associated with this future.
109 */
110 ChannelGroup group();
111
112 /**
113 * Returns the {@link ChannelFuture} of the individual I/O operation which
114 * is associated with the specified {@link Channel}.
115 *
116 * @return the matching {@link ChannelFuture} if found.
117 * {@code null} otherwise.
118 */
119 ChannelFuture find(Channel channel);
120
121 /**
122 * Returns {@code true} if and only if all I/O operations associated with
123 * this future were successful without any failure.
124 */
125 @Override
126 boolean isSuccess();
127
128 @Override
129 ChannelGroupException cause();
130
131 /**
132 * Returns {@code true} if and only if the I/O operations associated with
133 * this future were partially successful with some failure.
134 */
135 boolean isPartialSuccess();
136
137 /**
138 * Returns {@code true} if and only if the I/O operations associated with
139 * this future have failed partially with some success.
140 */
141 boolean isPartialFailure();
142
143 @Override
144 ChannelGroupFuture addListener(GenericFutureListener<? extends Future<? super Void>> listener);
145
146 @Override
147 ChannelGroupFuture addListeners(GenericFutureListener<? extends Future<? super Void>>... listeners);
148
149 @Override
150 ChannelGroupFuture removeListener(GenericFutureListener<? extends Future<? super Void>> listener);
151
152 @Override
153 ChannelGroupFuture removeListeners(GenericFutureListener<? extends Future<? super Void>>... listeners);
154
155 @Override
156 ChannelGroupFuture await() throws InterruptedException;
157
158 @Override
159 ChannelGroupFuture awaitUninterruptibly();
160
161 @Override
162 ChannelGroupFuture syncUninterruptibly();
163
164 @Override
165 ChannelGroupFuture sync() throws InterruptedException;
166
167 /**
168 * Returns the {@link Iterator} that enumerates all {@link ChannelFuture}s
169 * which are associated with this future. Please note that the returned
170 * {@link Iterator} is unmodifiable, which means a {@link ChannelFuture}
171 * cannot be removed from this future.
172 */
173 @Override
174 Iterator<ChannelFuture> iterator();
175 }