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 }