All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.gravitee.rest.api.service.vertx.VertxCompletableFuture Maven / Gradle / Ivy

There is a newer version: 3.10.0
Show newest version
/**
 * 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 anyOf(Vertx vertx, CompletableFuture... futures) { CompletableFuture all = CompletableFuture.anyOf(futures); return VertxCompletableFuture.from(vertx, 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 context 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 anyOf(Context context, CompletableFuture... futures) { CompletableFuture all = CompletableFuture.anyOf(futures); return VertxCompletableFuture.from(context, all); } // ============= with context methods ============= /** * Creates a new {@link VertxCompletableFuture} using the current context. This method is used to switch between * Vert.x contexts. * * @return the created {@link VertxCompletableFuture} */ public VertxCompletableFuture withContext() { Context context = Objects.requireNonNull(Vertx.currentContext()); return withContext(context); } /** * Creates a new {@link VertxCompletableFuture} using the current context or creates a new one. This method is used * to switch between Vert.x contexts. * * @return the created {@link VertxCompletableFuture} */ public VertxCompletableFuture withContext(Vertx vertx) { return withContext(Objects.requireNonNull(vertx).getOrCreateContext()); } /** * Creates a new {@link VertxCompletableFuture} using the given context. This method is used to switch between * Vert.x contexts. * * @return the created {@link VertxCompletableFuture} */ public VertxCompletableFuture withContext(Context context) { VertxCompletableFuture future = new VertxCompletableFuture<>(Objects.requireNonNull(context)); whenComplete( (res, err) -> { if (err != null) { future.completeExceptionally(err); } else { future.complete(res); } } ); return future; } /** * @return the context associated with the current {@link VertxCompletableFuture}. */ public Context context() { return context; } // ============= Composite Future implementation ============= @Override public VertxCompletableFuture thenApply(Function fn) { return new VertxCompletableFuture<>(context, super.thenApply(fn)); } @Override public VertxCompletableFuture thenApplyAsync(Function fn, Executor executor) { return new VertxCompletableFuture<>(context, super.thenApplyAsync(fn, executor)); } @Override public VertxCompletableFuture thenAcceptAsync(Consumer action, Executor executor) { return new VertxCompletableFuture<>(context, super.thenAcceptAsync(action, executor)); } @Override public VertxCompletableFuture thenRun(Runnable action) { return new VertxCompletableFuture<>(context, super.thenRun(action)); } @Override public VertxCompletableFuture thenRunAsync(Runnable action, Executor executor) { return new VertxCompletableFuture<>(context, super.thenRunAsync(action, executor)); } @Override public VertxCompletableFuture thenCombine( CompletionStage other, BiFunction fn ) { return new VertxCompletableFuture<>(context, super.thenCombine(other, fn)); } @Override public VertxCompletableFuture thenAcceptBoth(CompletionStage other, BiConsumer action) { return new VertxCompletableFuture<>(context, super.thenAcceptBoth(other, action)); } @Override public VertxCompletableFuture thenAcceptBothAsync( CompletionStage other, BiConsumer action, Executor executor ) { return new VertxCompletableFuture<>(context, super.thenAcceptBothAsync(other, action, executor)); } @Override public VertxCompletableFuture runAfterBoth(CompletionStage other, Runnable action) { return new VertxCompletableFuture<>(context, super.runAfterBoth(other, action)); } @Override public VertxCompletableFuture runAfterBothAsync(CompletionStage other, Runnable action, Executor executor) { return new VertxCompletableFuture<>(context, super.runAfterBothAsync(other, action, executor)); } @Override public VertxCompletableFuture applyToEither(CompletionStage other, Function fn) { return new VertxCompletableFuture<>(context, super.applyToEither(other, fn)); } @Override public VertxCompletableFuture applyToEitherAsync( CompletionStage other, Function fn, Executor executor ) { return new VertxCompletableFuture<>(context, super.applyToEitherAsync(other, fn, executor)); } @Override public VertxCompletableFuture acceptEither(CompletionStage other, Consumer action) { return new VertxCompletableFuture<>(context, super.acceptEither(other, action)); } @Override public VertxCompletableFuture acceptEitherAsync( CompletionStage other, Consumer action, Executor executor ) { return new VertxCompletableFuture<>(context, super.acceptEitherAsync(other, action, executor)); } @Override public VertxCompletableFuture runAfterEither(CompletionStage other, Runnable action) { return new VertxCompletableFuture<>(context, super.runAfterEither(other, action)); } @Override public VertxCompletableFuture runAfterEitherAsync(CompletionStage other, Runnable action, Executor executor) { return new VertxCompletableFuture<>(context, super.runAfterEitherAsync(other, action, executor)); } @Override public VertxCompletableFuture thenCompose(Function> fn) { return new VertxCompletableFuture<>(context, super.thenCompose(fn)); } @Override public VertxCompletableFuture whenComplete(BiConsumer action) { return new VertxCompletableFuture<>(context, super.whenComplete(action)); } @Override public VertxCompletableFuture whenCompleteAsync(BiConsumer action, Executor executor) { return new VertxCompletableFuture<>(context, super.whenCompleteAsync(action, executor)); } @Override public VertxCompletableFuture handle(BiFunction fn) { return new VertxCompletableFuture<>(context, super.handle(fn)); } @Override public VertxCompletableFuture handleAsync(BiFunction fn, Executor executor) { return new VertxCompletableFuture<>(context, super.handleAsync(fn, executor)); } @Override public VertxCompletableFuture thenApplyAsync(Function fn) { return new VertxCompletableFuture<>(context, super.thenApplyAsync(fn, executor)); } @Override public VertxCompletableFuture thenAccept(Consumer action) { return new VertxCompletableFuture<>(context, super.thenAccept(action)); } @Override public VertxCompletableFuture thenAcceptAsync(Consumer action) { return new VertxCompletableFuture<>(context, super.thenAcceptAsync(action, executor)); } @Override public VertxCompletableFuture thenRunAsync(Runnable action) { return new VertxCompletableFuture<>(context, super.thenRunAsync(action, executor)); } @Override public VertxCompletableFuture thenCombineAsync( CompletionStage other, BiFunction fn ) { return new VertxCompletableFuture<>(context, super.thenCombineAsync(other, fn, executor)); } @Override public VertxCompletableFuture thenAcceptBothAsync( CompletionStage other, BiConsumer action ) { return new VertxCompletableFuture<>(context, super.thenAcceptBothAsync(other, action, executor)); } @Override public VertxCompletableFuture runAfterBothAsync(CompletionStage other, Runnable action) { return new VertxCompletableFuture<>(context, super.runAfterBothAsync(other, action, executor)); } @Override public VertxCompletableFuture applyToEitherAsync(CompletionStage other, Function fn) { return new VertxCompletableFuture<>(context, super.applyToEitherAsync(other, fn, executor)); } @Override public VertxCompletableFuture acceptEitherAsync(CompletionStage other, Consumer action) { return new VertxCompletableFuture<>(context, super.acceptEitherAsync(other, action, executor)); } @Override public VertxCompletableFuture runAfterEitherAsync(CompletionStage other, Runnable action) { return new VertxCompletableFuture<>(context, super.runAfterEitherAsync(other, action, executor)); } @Override public VertxCompletableFuture thenComposeAsync(Function> fn) { return new VertxCompletableFuture<>(context, super.thenComposeAsync(fn, executor)); } @Override public VertxCompletableFuture thenComposeAsync(Function> fn, Executor executor) { return new VertxCompletableFuture<>(context, super.thenComposeAsync(fn, executor)); } public VertxCompletableFuture thenCombineAsync( CompletionStage other, BiFunction fn, Executor executor ) { return new VertxCompletableFuture<>(context, super.thenCombineAsync(other, fn, executor)); } @Override public VertxCompletableFuture whenCompleteAsync(BiConsumer action) { return new VertxCompletableFuture<>(context, super.whenCompleteAsync(action, executor)); } @Override public VertxCompletableFuture handleAsync(BiFunction fn) { return new VertxCompletableFuture<>(context, super.handleAsync(fn, executor)); } @Override public VertxCompletableFuture toCompletableFuture() { return this; } // ============= other instance methods ============= /** * Creates a new {@link Future} object completed / failed when the current {@link VertxCompletableFuture} is * completed successfully or not. * * @return the {@link Future}. */ public Future toFuture() { return VertxCompletableFuture.toFuture(this); } private void complete(T result, Throwable error) { if (error == null) { super.complete(result); } else { super.completeExceptionally(error); } } private void completeFromAsyncResult(AsyncResult ar) { if (ar.succeeded()) { super.complete(ar.result()); } else { super.completeExceptionally(ar.cause()); } } }