View Javadoc
1   /*
2    * Copyright 2013 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.util.concurrent;
17  
18  import java.util.concurrent.TimeUnit;
19  import java.util.function.Function;
20  
21  /**
22   * The result of an asynchronous operation.
23   * <p>
24   * An asynchronous operation is one that might be completed outside a given thread of execution. The operation can
25   * either be performing computation, or I/O, or both.
26   * <p>
27   * All I/O operations in Netty are asynchronous. It means any I/O calls will return immediately with no guarantee that
28   * the requested I/O operation has been completed at the end of the call. Instead, you will be returned with a {@link
29   * Future} instance which gives you the information about the result or status of the I/O operation.
30   * <p>
31   * A {@link Future} is either <em>uncompleted</em> or <em>completed</em>. When an I/O operation begins, a new future
32   * object is created. The new future is uncompleted initially - it is neither succeeded, failed, nor cancelled because
33   * the I/O operation is not finished yet. If the I/O operation is finished either successfully, with failure, or by
34   * cancellation, the future is marked as completed with more specific information, such as the cause of the failure.
35   * Please note that even failure and cancellation belong to the completed state.
36   * <pre>
37   *                                      +---------------------------+
38   *                                      | Completed successfully    |
39   *                                      +---------------------------+
40   *                                 +---->      isDone() = true      |
41   * +--------------------------+    |    |   isSuccess() = true      |
42   * |        Uncompleted       |    |    +===========================+
43   * +--------------------------+    |    | Completed with failure    |
44   * |      isDone() = false    |    |    +---------------------------+
45   * |   isSuccess() = false    |----+---->      isDone() = true      |
46   * | isCancelled() = false    |    |    |       cause() = non-null  |
47   * |       cause() = throws   |    |    +===========================+
48   * |      getNow() = throws   |    |    | Completed by cancellation |
49   * +--------------------------+    |    +---------------------------+
50   *                                 +---->      isDone() = true      |
51   *                                      | isCancelled() = true      |
52   *                                      +---------------------------+
53   * </pre>
54   * <p>
55   * Various methods are provided to let you check if the I/O operation has been completed, wait for the completion, and
56   * retrieve the result of the I/O operation. It also allows you to add {@link FutureListener}s so you can get notified
57   * when the I/O operation is completed.
58   *
59   * <h3>Prefer {@link #addListener(FutureListener)} to {@link FutureCompletionStage#await()}</h3>
60   * <p>
61   * It is recommended to prefer {@link #addListener(FutureListener)}, or {@link #addListener(Object,
62   * FutureContextListener)}, to {@link FutureCompletionStage#await()} wherever possible to get notified when an I/O
63   * operation is done and to do any follow-up tasks.
64   * <p>
65   * The {@link #addListener(FutureListener)} method is non-blocking. It simply adds the specified {@link FutureListener}
66   * to the {@link Future}, and the I/O thread will notify the listeners when the I/O operation associated with the future
67   * is done. The {@link FutureListener} and {@link FutureContextListener} callbacks yield the best performance and
68   * resource utilization because it does not block at all, but it could be tricky to implement a sequential logic if you
69   * are not used to event-driven programming.
70   * <p>
71   * By contrast, {@link FutureCompletionStage#await()} is a blocking operation. Once called, the caller thread blocks
72   * until the operation is done. It is easier to implement a sequential logic with {@link FutureCompletionStage#await()},
73   * but the caller thread blocks unnecessarily until the I/O operation is done and there's relatively expensive cost of
74   * inter-thread notification. Moreover, there's a chance of deadlock in a particular circumstance, which is
75   * described below.
76   *
77   * <h3>Do not call {@link FutureCompletionStage#await()} inside a {@link io.netty5.channel.ChannelHandler}</h3>
78   * <p>
79   * The event handler methods in {@link io.netty5.channel.ChannelHandler} are usually called by an I/O thread.
80   * If {@link FutureCompletionStage#await()} is called by an event handler method, which is called by the I/O thread,
81   * the I/O operation it is waiting for might never complete because {@link FutureCompletionStage#await()} can block
82   * the I/O operation it is waiting for, which is a deadlock.
83   * <pre>
84   * // BAD - NEVER DO THIS
85   * {@code @Override}
86   * public void channelRead({@link io.netty5.channel.ChannelHandlerContext} ctx, Object msg) {
87   *     {@link Future} future = ctx.channel().close();
88   *     future.asStage().await();
89   *     // Perform post-closure operation
90   *     // ...
91   * }
92   *
93   * // GOOD
94   * {@code @Override}
95   * public void channelRead({@link io.netty5.channel.ChannelHandlerContext} ctx, Object msg) {
96   *     {@link Future} future = ctx.channel().close();
97   *     future.addListener(new {@link FutureListener}() {
98   *         public void operationComplete({@link Future} future) {
99   *             // Perform post-closure operation
100  *             // ...
101  *         }
102  *     });
103  * }
104  * </pre>
105  * <p>
106  * In spite of the disadvantages mentioned above, there are certainly the cases where it is more convenient to call
107  * {@link FutureCompletionStage#await()}. In such a case, please make sure you do not call
108  * {@link FutureCompletionStage#await()} in an I/O thread. Otherwise, {@link BlockingOperationException} will be
109  * raised to prevent a deadlock.
110  *
111  * <h3>Do not confuse I/O timeout and await timeout</h3>
112  * <p>
113  * The timeout value you specify with {@link FutureCompletionStage#await(long, TimeUnit)} is not related to the
114  * I/O timeout at all.
115  * If an I/O operation times out, the future will be marked as 'completed with failure,' as depicted in the
116  * diagram above.  For example, connect timeout should be configured via a transport-specific option:
117  * <pre>
118  * // BAD - NEVER DO THIS
119  * {@link io.netty5.bootstrap.Bootstrap} b = ...;
120  * {@link Future} f = b.connect(...);
121  * f.asStage().await(10, TimeUnit.SECONDS);
122  * if (f.isCancelled()) {
123  *     // Connection attempt cancelled by user
124  * } else if (!f.isSuccess()) {
125  *     // You might get a NullPointerException here because the future
126  *     // might not be completed yet.
127  *     f.cause().printStackTrace();
128  * } else {
129  *     // Connection established successfully
130  * }
131  *
132  * // GOOD
133  * {@link io.netty5.bootstrap.Bootstrap} b = ...;
134  * // Configure the connect timeout option.
135  * <b>b.option({@link io.netty5.channel.ChannelOption}.CONNECT_TIMEOUT_MILLIS, 10000);</b>
136  * {@link Future} f = b.connect(...);
137  * f.asStage().await();
138  *
139  * // Now we are sure the future is completed.
140  * assert f.isDone();
141  *
142  * if (f.isCancelled()) {
143  *     // Connection attempt cancelled by user
144  * } else if (!f.isSuccess()) {
145  *     f.cause().printStackTrace();
146  * } else {
147  *     // Connection established successfully
148  * }
149  * </pre>
150  */
151 public interface Future<V> extends AsynchronousResult<V> {
152     /**
153      * Adds the specified listener to this future. The specified listener is notified when this future is {@linkplain
154      * #isDone() done}. If this future is already completed, the specified listener is notified immediately.
155      *
156      * @param listener The listener to be called when this future completes. The listener will be passed this future as
157      *                 an argument.
158      * @return this future object.
159      */
160     Future<V> addListener(FutureListener<? super V> listener);
161 
162     /**
163      * Adds the specified listener to this future. The specified listener is notified when this future is {@linkplain
164      * #isDone() done}. If this future is already completed, the specified listener is notified immediately.
165      *
166      * @param context  The context object that will be passed to the listener when this future completes.
167      * @param listener The listener to be called when this future completes. The listener will be passed the given
168      *                 context, and this future.
169      * @return this future object.
170      */
171     <C> Future<V> addListener(C context, FutureContextListener<? super C, ? super V> listener);
172 
173     /**
174      * Returns a {@link FutureCompletionStage} that reflects the state of this {@link Future} and so will receive all
175      * updates as well.
176      * <p>
177      * The returned {@link FutureCompletionStage} also implements the JDK {@link java.util.concurrent.Future},
178      * and has blocking methods not found on the Netty {@code Future} interface, for awaiting the completion.
179      */
180     FutureCompletionStage<V> asStage();
181 
182     /**
183      * Creates a <strong>new</strong> {@link Future} that will complete with the result of this {@link Future} mapped
184      * through the given mapper function.
185      * <p>
186      * If this future fails, then the returned future will fail as well, with the same exception. Cancellation of either
187      * future will cancel the other. If the mapper function throws, the returned future will fail, but this future will
188      * be unaffected.
189      *
190      * @param mapper The function that will convert the result of this future into the result of the returned future.
191      * @param <R>    The result type of the mapper function, and of the returned future.
192      * @return A new future instance that will complete with the mapped result of this future.
193      */
194     default <R> Future<R> map(Function<V, R> mapper) {
195         return Futures.map(this, mapper);
196     }
197 
198     /**
199      * Creates a <strong>new</strong> {@link Future} that will complete with the result of this {@link Future}
200      * flat-mapped through the given mapper function.
201      * <p>
202      * The "flat" in "flat-map" means the given mapper function produces a result that itself is a future-of-R, yet this
203      * method also returns a future-of-R, rather than a future-of-future-of-R. In other words, if the same mapper
204      * function was used with the {@link #map(Function)} method, you would get back a {@code Future<Future<R>>}. These
205      * nested futures are "flattened" into a {@code Future<R>} by this method.
206      * <p>
207      * Effectively, this method behaves similar to this serial code, except asynchronously and with proper exception and
208      * cancellation handling:
209      * <pre>{@code
210      * V x = future.sync().getNow();
211      * Future<R> y = mapper.apply(x);
212      * R result = y.sync().getNow();
213      * }</pre>
214      * <p>
215      * If the given future fails, then the returned future will fail as well, with the same exception. Cancellation of
216      * either future will cancel the other. If the mapper function throws, the returned future will fail, but this
217      * future will be unaffected.
218      *
219      * @param mapper The function that will convert the result of this future into the result of the returned future.
220      * @param <R>    The result type of the mapper function, and of the returned future.
221      * @return A new future instance that will complete with the mapped result of this future.
222      */
223     default <R> Future<R> flatMap(Function<V, Future<R>> mapper) {
224         return Futures.flatMap(this, mapper);
225     }
226 
227     /**
228      * Link the {@link Future} and {@link Promise} such that if the {@link Future} completes the {@link Promise}
229      * will be notified. Cancellation is propagated both ways such that if the {@link Future} is cancelled
230      * the {@link Promise} is cancelled and vice-versa.
231      *
232      * @param promise   the {@link Promise} which will be notified
233      * @return          itself
234      */
235     default Future<V> cascadeTo(final Promise<? super V> promise) {
236         Futures.cascade(this, promise);
237         return this;
238     }
239 }