io.gravitee.rest.api.service.vertx.VertxCompletableFuture Maven / Gradle / Ivy
/**
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.gravitee.rest.api.service.vertx;
import io.vertx.core.AsyncResult;
import io.vertx.core.Context;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.*;
/**
* An implementation of {@link CompletableFuture} for Vert.x. It differs in the way to handle async calls:
*
* * {@link VertxCompletableFuture} are attached to a Vert.x {@link Context}
* * All operator methods returns {@link VertxCompletableFuture}
* * method not passing an {@link Executor} are executed on the attached {@link Context}
* * All non async method are executed on the current Thread (so not necessary on the attached {@link Context}
*
* The class also offer bridges methods with Vert.x {@link Future}, and regular {@link CompletableFuture}.
*
* @param the expected type of result
*/
@SuppressWarnings("WeakerAccess")
public class VertxCompletableFuture extends CompletableFuture implements CompletionStage {
private final Executor executor;
/**
* The {@link Context} used by the future.
*/
private final Context context;
// ============= Constructors =============
/**
* Creates an instance of {@link VertxCompletableFuture}, using the current Vert.x context or create a new one.
*
* @param vertx the Vert.x instance
*/
public VertxCompletableFuture(Vertx vertx) {
this(Objects.requireNonNull(vertx).getOrCreateContext());
}
/**
* Creates an instance of {@link VertxCompletableFuture}, using the given {@link Context}.
*
* @param context the context
*/
public VertxCompletableFuture(Context context) {
this.context = Objects.requireNonNull(context);
this.executor = command -> context.runOnContext(v -> command.run());
}
/**
* Creates a new {@link VertxCompletableFuture} from the given context and given {@link CompletableFuture}.
* The created {@link VertxCompletableFuture} is completed successfully or not when the given completable future
* completes successfully or not.
*
* @param context the context
* @param future the completable future
*/
private VertxCompletableFuture(Context context, CompletableFuture future) {
this(context);
Objects
.requireNonNull(future)
.whenComplete(
(res, err) -> {
if (err != null) {
completeExceptionally(err);
} else {
complete(res);
}
}
);
}
/**
* Creates a new {@link VertxCompletableFuture} using the current {@link Context}. This method
* must be used from a Vert.x thread, or fails.
*/
public VertxCompletableFuture() {
this(Vertx.currentContext());
}
// ============= Factory methods (from) =============
/**
* Creates a new {@link VertxCompletableFuture} from the given {@link Vertx} instance and given
* {@link CompletableFuture}. The returned future uses the current Vert.x context, or creates a new one.
*
* The created {@link VertxCompletableFuture} is completed successfully or not when the given completable future
* completes successfully or not.
*
* @param vertx the Vert.x instance
* @param future the future
* @param the type of the result
* @return the new {@link VertxCompletableFuture}
*/
public static VertxCompletableFuture from(Vertx vertx, CompletableFuture future) {
return from(vertx.getOrCreateContext(), future);
}
/**
* Creates a new {@link VertxCompletableFuture} from the given {@link Context} instance and given
* {@link Future}. The returned future uses the current Vert.x context, or creates a new one.
*
* The created {@link VertxCompletableFuture} is completed successfully or not when the given future
* completes successfully or not.
*
* @param vertx the Vert.x instance
* @param future the Vert.x future
* @param the type of the result
* @return the new {@link VertxCompletableFuture}
*/
public static VertxCompletableFuture from(Vertx vertx, Future future) {
return from(vertx.getOrCreateContext(), future);
}
/**
* Creates a {@link VertxCompletableFuture} from the given {@link Context} and {@link CompletableFuture}.
*
* The created {@link VertxCompletableFuture} is completed successfully or not when the given future
* completes successfully or not. The completion is called on the given {@link Context}, immediately if it is
* already executing on the right context, asynchronously if not.
*
* @param context the context
* @param future the future
* @param the type of result
* @return the creation {@link VertxCompletableFuture}
*/
public static VertxCompletableFuture from(Context context, CompletableFuture future) {
VertxCompletableFuture res = new VertxCompletableFuture<>(Objects.requireNonNull(context));
Objects
.requireNonNull(future)
.whenComplete(
(result, error) -> {
if (context == Vertx.currentContext()) {
res.complete(result, error);
} else {
res.context.runOnContext(v -> res.complete(result, error));
}
}
);
return res;
}
/**
* Creates a new {@link VertxCompletableFuture} from the given {@link Context} instance and given
* {@link Future}. The returned future uses the current Vert.x context, or creates a new one.
*
* The created {@link VertxCompletableFuture} is completed successfully or not when the given future
* completes successfully or not. The created {@link VertxCompletableFuture} is completed successfully or not
* when the given future completes successfully or not. The completion is called on the given {@link Context},
* immediately if it is already executing on the right context, asynchronously if not.
*
* @param context the context
* @param future the Vert.x future
* @param the type of the result
* @return the new {@link VertxCompletableFuture}
*/
public static VertxCompletableFuture from(Context context, Future future) {
VertxCompletableFuture res = new VertxCompletableFuture<>(Objects.requireNonNull(context));
Objects
.requireNonNull(future)
.setHandler(
ar -> {
if (context == Vertx.currentContext()) {
res.completeFromAsyncResult(ar);
} else {
res.context.runOnContext(v -> res.completeFromAsyncResult(ar));
}
}
);
return res;
}
/**
* Returns a new CompletableFuture that is asynchronously completed by a task running in the current Vert.x
* {@link Context} with the value obtained by calling the given Supplier.
*
* This method is different from {@link CompletableFuture#supplyAsync(Supplier)} as it does not use a fork join
* executor, but use the Vert.x context.
*
* @param vertx the Vert.x instance
* @param supplier a function returning the value to be used to complete the returned CompletableFuture
* @param the function's return type
* @return the new CompletableFuture
*/
public static VertxCompletableFuture supplyAsync(Vertx vertx, Supplier supplier) {
return supplyAsync(Objects.requireNonNull(vertx).getOrCreateContext(), supplier);
}
/**
* Returns a new CompletableFuture that is asynchronously completed by a task running in the
* current Vert.x {@link Context} after it runs the given action.
*
* This method is different from {@link CompletableFuture#supplyAsync(Supplier)} as it does not use a fork join
* executor, but use the Vert.x context.
*
* @param vertx the Vert.x instance
* @param runnable the action to run before completing the returned CompletableFuture
* @return the new CompletableFuture
*/
public static VertxCompletableFuture runAsync(Vertx vertx, Runnable runnable) {
return runAsync(Objects.requireNonNull(vertx).getOrCreateContext(), runnable);
}
/**
* Returns a new CompletableFuture that is asynchronously completed by a task running in the current Vert.x
* {@link Context} with the value obtained by calling the given Supplier.
*
* This method is different from {@link CompletableFuture#supplyAsync(Supplier)} as it does not use a fork join
* executor, but use the Vert.x context.
*
* @param context the context in which the supplier is executed.
* @param supplier a function returning the value to be used to complete the returned CompletableFuture
* @param the function's return type
* @return the new CompletableFuture
*/
public static VertxCompletableFuture supplyAsync(Context context, Supplier supplier) {
Objects.requireNonNull(supplier);
VertxCompletableFuture future = new VertxCompletableFuture<>(Objects.requireNonNull(context));
context.runOnContext(
v -> {
try {
future.complete(supplier.get());
} catch (Throwable e) {
future.completeExceptionally(e);
}
}
);
return future;
}
/**
* Returns a new CompletableFuture that is asynchronously completed by a task running in the
* current Vert.x {@link Context} after it runs the given action.
*
* This method is different from {@link CompletableFuture#runAsync(Runnable)} as it does not use a fork join
* executor, but use the Vert.x context.
*
* @param context the context
* @param runnable the action to run before completing the returned CompletableFuture
* @return the new CompletableFuture
*/
public static VertxCompletableFuture runAsync(Context context, Runnable runnable) {
Objects.requireNonNull(runnable);
VertxCompletableFuture future = new VertxCompletableFuture<>(context);
context.runOnContext(
v -> {
try {
runnable.run();
future.complete(null);
} catch (Throwable e) {
future.completeExceptionally(e);
}
}
);
return future;
}
/**
* Returns a new CompletableFuture that is asynchronously completed by a task running in the worker thread pool of
* Vert.x
*
* This method is different from {@link CompletableFuture#supplyAsync(Supplier)} as it does not use a fork join
* executor, but the worker thread pool.
*
* @param vertx the Vert.x instance
* @param supplier a function returning the value to be used to complete the returned CompletableFuture
* @param the function's return type
* @return the new CompletableFuture
*/
public static VertxCompletableFuture supplyBlockingAsync(Vertx vertx, Supplier supplier) {
return supplyBlockingAsync(Objects.requireNonNull(vertx).getOrCreateContext(), supplier);
}
/**
* Returns a new CompletableFuture that is asynchronously completed by a action running in the worker thread pool of
* Vert.x
*
* This method is different from {@link CompletableFuture#runAsync(Runnable)} as it does not use a fork join
* executor, but the worker thread pool.
*
* @param vertx the Vert.x instance
* @param runnable the action, when its execution completes, it completes the returned CompletableFuture. If the
* execution throws an exception, the returned CompletableFuture is completed exceptionally.
* @return the new CompletableFuture
*/
public static VertxCompletableFuture runBlockingAsync(Vertx vertx, Runnable runnable) {
return runBlockingAsync(Objects.requireNonNull(vertx).getOrCreateContext(), runnable);
}
/**
* Returns a new CompletableFuture that is asynchronously completed by a action running in the worker thread pool of
* Vert.x
*
* This method is different from {@link CompletableFuture#runAsync(Runnable)} as it does not use a fork join
* executor, but the worker thread pool.
*
* @param context the Vert.x context
* @param runnable the action, when its execution completes, it completes the returned CompletableFuture. If the
* execution throws an exception, the returned CompletableFuture is completed exceptionally.
* @return the new CompletableFuture
*/
public static VertxCompletableFuture runBlockingAsync(Context context, Runnable runnable) {
Objects.requireNonNull(runnable);
VertxCompletableFuture future = new VertxCompletableFuture<>(Objects.requireNonNull(context));
context.executeBlocking(
fut -> {
try {
runnable.run();
future.complete(null);
} catch (Throwable e) {
future.completeExceptionally(e);
}
},
null
);
return future;
}
/**
* Returns a new CompletableFuture that is asynchronously completed by a task running in the worker thread pool of
* Vert.x
*
* This method is different from {@link CompletableFuture#supplyAsync(Supplier)} as it does not use a fork join
* executor, but the worker thread pool.
*
* @param context the context in which the supplier is executed.
* @param supplier a function returning the value to be used to complete the returned CompletableFuture
* @param the function's return type
* @return the new CompletableFuture
*/
public static VertxCompletableFuture supplyBlockingAsync(Context context, Supplier supplier) {
Objects.requireNonNull(supplier);
VertxCompletableFuture future = new VertxCompletableFuture<>(context);
context.executeBlocking(
fut -> {
try {
fut.complete(supplier.get());
} catch (Throwable e) {
fut.fail(e);
}
},
ar -> {
if (ar.failed()) {
future.completeExceptionally(ar.cause());
} else {
future.complete(ar.result());
}
}
);
return future;
}
// ============= Wrapping methods =============
/**
* Creates a Vert.x {@link Future} from the given {@link CompletableFuture} (that can be a
* {@link VertxCompletableFuture}).
*
* @param future the future
* @param the type of the result
* @return the Vert.x future completed or failed when the given {@link CompletableFuture} completes or fails.
*/
public static Future toFuture(CompletableFuture future) {
Future fut = Future.future();
Objects
.requireNonNull(future)
.whenComplete(
(res, err) -> {
if (err != null) {
fut.fail(err);
} else {
fut.complete(res);
}
}
);
return fut;
}
// ============= Parallel composition methods =============
/**
* Returns a new CompletableFuture that is completed when all of the given CompletableFutures complete. If any of
* the given CompletableFutures complete exceptionally, then the returned CompletableFuture also does so, with a
* CompletionException holding this exception as its cause. Otherwise, the results, if any, of the given
* CompletableFutures are not reflected in the returned CompletableFuture, but may be obtained by inspecting them
* individually. If no CompletableFutures are provided, returns a CompletableFuture completed with the value
* {@code null}.
*
*
Among the applications of this method is to await completion
* of a set of independent CompletableFutures before continuing a
* program, as in: {@code CompletableFuture.allOf(c1, c2, c3).join();}.
*
* Unlike the original {@link CompletableFuture#allOf(CompletableFuture[])} this method invokes the dependent
* stages into the Vert.x context.
*
* @param vertx the Vert.x instance to retrieve the context
* @param futures the CompletableFutures
* @return a new CompletableFuture that is completed when all of the given CompletableFutures complete
* @throws NullPointerException if the array or any of its elements are {@code null}
*/
public static VertxCompletableFuture allOf(Vertx vertx, CompletableFuture>... futures) {
CompletableFuture all = CompletableFuture.allOf(futures);
return VertxCompletableFuture.from(vertx, all);
}
/**
* Returns a new CompletableFuture that is completed when all of the given CompletableFutures complete. If any of
* the given CompletableFutures complete exceptionally, then the returned CompletableFuture also does so, with a
* CompletionException holding this exception as its cause. Otherwise, the results, if any, of the given
* CompletableFutures are not reflected in the returned CompletableFuture, but may be obtained by inspecting them
* individually. If no CompletableFutures are provided, returns a CompletableFuture completed with the value
* {@code null}.
*
*
Among the applications of this method is to await completion
* of a set of independent CompletableFutures before continuing a
* program, as in: {@code CompletableFuture.allOf(c1, c2, c3).join();}.
*
* Unlike the original {@link CompletableFuture#allOf(CompletableFuture[])} this method invokes the dependent
* stages into the Vert.x context.
*
* @param context the context
* @param futures the CompletableFutures
* @return a new CompletableFuture that is completed when all of the given CompletableFutures complete
* @throws NullPointerException if the array or any of its elements are {@code null}
*/
public static VertxCompletableFuture allOf(Context context, CompletableFuture>... futures) {
CompletableFuture all = CompletableFuture.allOf(futures);
return VertxCompletableFuture.from(context, all);
}
/**
* Returns a new CompletableFuture that is completed when any of the given CompletableFutures complete, with the
* same result. Otherwise, if it completed exceptionally, the returned CompletableFuture also does so, with a
* CompletionException holding this exception as its cause. If no CompletableFutures are provided, returns an
* incomplete CompletableFuture.
*
* Unlike the original {@link CompletableFuture#allOf(CompletableFuture[])} this method invokes the dependent
* stages into the Vert.x context.
*
* @param vertx the Vert.x instance to retrieve the context
* @param futures the CompletableFutures
* @return a new CompletableFuture that is completed with the result or exception of any of the given
* CompletableFutures when one completes
* @throws NullPointerException if the array or any of its elements are {@code null}
*/
public static VertxCompletableFuture