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    *   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.netty5.channel.group;
17  
18  import io.netty5.channel.Channel;
19  import io.netty5.channel.ChannelHandler;
20  import io.netty5.channel.ChannelHandlerContext;
21  import io.netty5.util.concurrent.Future;
22  import io.netty5.util.concurrent.FutureCompletionStage;
23  import io.netty5.util.concurrent.FutureListener;
24  
25  import java.util.Iterator;
26  
27  /**
28   * The result of an asynchronous {@link ChannelGroup} operation.
29   * {@link ChannelGroupFuture} is composed of {@link Future}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(FutureListener)} to {@link FutureCompletionStage#await()}</h3>
47   *
48   * It is recommended to prefer {@link #addListener(FutureListener)} to
49   * {@link FutureCompletionStage#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(FutureListener)} 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 FutureCompletionStage#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 FutureCompletionStage#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 FutureCompletionStage#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 FutureCompletionStage#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 FutureCompletionStage#await()} can block the I/O
73   * operation it is waiting for, which is a deadlock.
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.asStage().await();
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 FutureCompletionStage#await()}. In such a case, please
102  * make sure you do not call {@link FutureCompletionStage#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<Future<Void>> {
106 
107     /**
108      * Returns the {@link ChannelGroup} which is associated with this future.
109      */
110     ChannelGroup group();
111 
112     /**
113      * Returns the {@link Future} of the individual I/O operation which
114      * is associated with the specified {@link Channel}.
115      *
116      * @return the matching {@link Future} if found.
117      *         {@code null} otherwise.
118      */
119     Future<Void> 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(FutureListener<? super Void> listener);
145 
146     /**
147      * Returns the {@link Iterator} that enumerates all {@link Future}s
148      * which are associated with this future.  Please note that the returned
149      * {@link Iterator} is is unmodifiable, which means a {@link Future}
150      * cannot be removed from this future.
151      */
152     @Override
153     Iterator<Future<Void>> iterator();
154 }