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

io.vertx.core.Future Maven / Gradle / Ivy

There is a newer version: 5.0.0.CR1
Show newest version
/*
 * Copyright (c) 2011-2019 Contributors to the Eclipse Foundation
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
 * which is available at https://www.apache.org/licenses/LICENSE-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
 */

package io.vertx.core;

import io.vertx.codegen.annotations.Fluent;
import io.vertx.codegen.annotations.GenIgnore;
import io.vertx.core.impl.ContextInternal;
import io.vertx.core.impl.Utils;
import io.vertx.core.impl.future.CompositeFutureImpl;
import io.vertx.core.impl.future.FailedFuture;
import io.vertx.core.impl.future.SucceededFuture;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * Represents the result of an action that may, or may not, have occurred yet.
 * 

* * @author Tim Fox */ public interface Future extends AsyncResult { /** * Return a composite future, succeeded when all futures are succeeded, failed when any future is failed. *

* The returned future fails as soon as one of {@code f1} or {@code f2} fails. * * @param f1 future * @param f2 future * @return the composite future */ static CompositeFuture all(Future f1, Future f2) { return CompositeFutureImpl.all(f1, f2); } /** * Like {@link #all(Future, Future)} but with 3 futures. */ static CompositeFuture all(Future f1, Future f2, Future f3) { return CompositeFutureImpl.all(f1, f2, f3); } /** * Like {@link #all(Future, Future)} but with 4 futures. */ static CompositeFuture all(Future f1, Future f2, Future f3, Future f4) { return CompositeFutureImpl.all(f1, f2, f3, f4); } /** * Like {@link #all(Future, Future)} but with 5 futures. */ static CompositeFuture all(Future f1, Future f2, Future f3, Future f4, Future f5) { return CompositeFutureImpl.all(f1, f2, f3, f4, f5); } /** * Like {@link #all(Future, Future)} but with 6 futures. */ static CompositeFuture all(Future f1, Future f2, Future f3, Future f4, Future f5, Future f6) { return CompositeFutureImpl.all(f1, f2, f3, f4, f5, f6); } /** * Like {@link #all(Future, Future)} but with a list of futures.

* * When the list is empty, the returned future will be already completed. */ static CompositeFuture all(List> futures) { return CompositeFutureImpl.all(futures.toArray(new Future[0])); } /** * Return a composite future, succeeded when any futures is succeeded, failed when all futures are failed. *

* The returned future succeeds as soon as one of {@code f1} or {@code f2} succeeds. * * @param f1 future * @param f2 future * @return the composite future */ static CompositeFuture any(Future f1, Future f2) { return CompositeFutureImpl.any(f1, f2); } /** * Like {@link #any(Future, Future)} but with 3 futures. */ static CompositeFuture any(Future f1, Future f2, Future f3) { return CompositeFutureImpl.any(f1, f2, f3); } /** * Like {@link #any(Future, Future)} but with 4 futures. */ static CompositeFuture any(Future f1, Future f2, Future f3, Future f4) { return CompositeFutureImpl.any(f1, f2, f3, f4); } /** * Like {@link #any(Future, Future)} but with 5 futures. */ static CompositeFuture any(Future f1, Future f2, Future f3, Future f4, Future f5) { return CompositeFutureImpl.any(f1, f2, f3, f4, f5); } /** * Like {@link #any(Future, Future)} but with 6 futures. */ static CompositeFuture any(Future f1, Future f2, Future f3, Future f4, Future f5, Future f6) { return CompositeFutureImpl.any(f1, f2, f3, f4, f5, f6); } /** * Like {@link #any(Future, Future)} but with a list of futures.

* * When the list is empty, the returned future will be already completed. */ static CompositeFuture any(List> futures) { return CompositeFutureImpl.any(futures.toArray(new Future[0])); } /** * Return a composite future, succeeded when all futures are succeeded, failed when any future is failed. *

* It always wait until all its futures are completed and will not fail as soon as one of {@code f1} or {@code f2} fails. * * @param f1 future * @param f2 future * @return the composite future */ static CompositeFuture join(Future f1, Future f2) { return CompositeFutureImpl.join(f1, f2); } /** * Like {@link #join(Future, Future)} but with 3 futures. */ static CompositeFuture join(Future f1, Future f2, Future f3) { return CompositeFutureImpl.join(f1, f2, f3); } /** * Like {@link #join(Future, Future)} but with 4 futures. */ static CompositeFuture join(Future f1, Future f2, Future f3, Future f4) { return CompositeFutureImpl.join(f1, f2, f3, f4); } /** * Like {@link #join(Future, Future)} but with 5 futures. */ static CompositeFuture join(Future f1, Future f2, Future f3, Future f4, Future f5) { return CompositeFutureImpl.join(f1, f2, f3, f4, f5); } /** * Like {@link #join(Future, Future)} but with 6 futures. */ static CompositeFuture join(Future f1, Future f2, Future f3, Future f4, Future f5, Future f6) { return CompositeFutureImpl.join(f1, f2, f3, f4, f5, f6); } /** * Like {@link #join(Future, Future)} but with a list of futures.

* * When the list is empty, the returned future will be already completed. */ static CompositeFuture join(List> futures) { return CompositeFutureImpl.join(futures.toArray(new Future[0])); } /** * Create a future that hasn't completed yet and that is passed to the {@code handler} before it is returned. * * @param handler the handler * @param the result type * @return the future. */ static Future future(Handler> handler) { Promise promise = Promise.promise(); try { handler.handle(promise); } catch (Throwable e){ promise.tryFail(e); } return promise.future(); } /** * Create a succeeded future with a null result * * @param the result type * @return the future */ static Future succeededFuture() { return (Future) SucceededFuture.EMPTY; } /** * Created a succeeded future with the specified result. * * @param result the result * @param the result type * @return the future */ static Future succeededFuture(T result) { if (result == null) { return succeededFuture(); } else { return new SucceededFuture<>(result); } } /** * Create a failed future with the specified failure cause. * * @param t the failure cause as a Throwable * @param the result type * @return the future */ static Future failedFuture(Throwable t) { return new FailedFuture<>(t); } /** * Create a failed future with the specified failure message. * * @param failureMessage the failure message * @param the result type * @return the future */ static Future failedFuture(String failureMessage) { return new FailedFuture<>(failureMessage); } /** * Has the future completed? *

* It's completed if it's either succeeded or failed. * * @return true if completed, false if not */ boolean isComplete(); /** * Add a handler to be notified of the result. *

* WARNING: this is a terminal operation. * If several {@code handler}s are registered, there is no guarantee that they will be invoked in order of registration. * * @param handler the handler that will be called with the result * @return a reference to this, so it can be used fluently */ @Fluent Future onComplete(Handler> handler); /** * Add handlers to be notified on succeeded result and failed result. *

* WARNING: this is a terminal operation. * If several {@code handler}s are registered, there is no guarantee that they will be invoked in order of registration. * * @param successHandler the handler that will be called with the succeeded result * @param failureHandler the handler that will be called with the failed result * @return a reference to this, so it can be used fluently */ default Future onComplete(Handler successHandler, Handler failureHandler) { return onComplete(ar -> { if (successHandler != null && ar.succeeded()) { successHandler.handle(ar.result()); } else if (failureHandler != null && ar.failed()) { failureHandler.handle(ar.cause()); } }); } /** * Add a handler to be notified of the succeeded result. *

* WARNING: this is a terminal operation. * If several {@code handler}s are registered, there is no guarantee that they will be invoked in order of registration. * * @param handler the handler that will be called with the succeeded result * @return a reference to this, so it can be used fluently */ @Fluent default Future onSuccess(Handler handler) { return onComplete(handler, null); } /** * Add a handler to be notified of the failed result. *

* WARNING: this is a terminal operation. * If several {@code handler}s are registered, there is no guarantee that they will be invoked in order of registration. * * @param handler the handler that will be called with the failed result * @return a reference to this, so it can be used fluently */ @Fluent default Future onFailure(Handler handler) { return onComplete(null, handler); } /** * The result of the operation. This will be null if the operation failed. * * @return the result or null if the operation failed. */ @Override T result(); /** * A Throwable describing failure. This will be null if the operation succeeded. * * @return the cause or null if the operation succeeded. */ @Override Throwable cause(); /** * Did it succeed? * * @return true if it succeded or false otherwise */ @Override boolean succeeded(); /** * Did it fail? * * @return true if it failed or false otherwise */ @Override boolean failed(); /** * Alias for {@link #compose(Function)}. */ default Future flatMap(Function> mapper) { return compose(mapper); } /** * Compose this future with a {@code mapper} function.

* * When this future (the one on which {@code compose} is called) succeeds, the {@code mapper} will be called with * the completed value and this mapper returns another future object. This returned future completion will complete * the future returned by this method call.

* * If the {@code mapper} throws an exception, the returned future will be failed with this exception.

* * When this future fails, the failure will be propagated to the returned future and the {@code mapper} * will not be called. * * @param mapper the mapper function * @return the composed future */ default Future compose(Function> mapper) { return compose(mapper, Future::failedFuture); } /** * Handles a failure of this Future by returning the result of another Future. * If the mapper fails, then the returned future will be failed with this failure. * * @param mapper A function which takes the exception of a failure and returns a new future. * @return A recovered future */ default Future recover(Function> mapper) { return compose(Future::succeededFuture, mapper); } /** * Compose this future with a {@code successMapper} and {@code failureMapper} functions.

* * When this future (the one on which {@code compose} is called) succeeds, the {@code successMapper} will be called with * the completed value and this mapper returns another future object. This returned future completion will complete * the future returned by this method call.

* * When this future (the one on which {@code compose} is called) fails, the {@code failureMapper} will be called with * the failure and this mapper returns another future object. This returned future completion will complete * the future returned by this method call.

* * If any mapper function throws an exception, the returned future will be failed with this exception.

* * @param successMapper the function mapping the success * @param failureMapper the function mapping the failure * @return the composed future */ Future compose(Function> successMapper, Function> failureMapper); /** * Transform this future with a {@code mapper} functions.

* * When this future (the one on which {@code transform} is called) completes, the {@code mapper} will be called with * the async result and this mapper returns another future object. This returned future completion will complete * the future returned by this method call.

* * If any mapper function throws an exception, the returned future will be failed with this exception.

* * @param mapper the function mapping the future * @return the transformed future */ Future transform(Function, Future> mapper); /** * Compose this future with a {@code function} that will be always be called. * *

When this future (the one on which {@code eventually} is called) completes, the {@code function} will be called * and this mapper returns another future object. This returned future completion will complete the future returned * by this method call with the original result of the future. * *

The outcome of the future returned by the {@code function} will not influence the nature * of the returned future. * * @param function the function returning the future. * @return the composed future * @deprecated instead use {@link #eventually(Supplier)}, this method will be removed in Vert.x 5 */ @Deprecated Future eventually(Function> function); /** * Compose this future with a {@code supplier} that will be always be called. * *

When this future (the one on which {@code eventually} is called) completes, the {@code supplier} will be called * and this mapper returns another future object. This returned future completion will complete the future returned * by this method call with the original result of the future. * *

The outcome of the future returned by the {@code supplier} will not influence the nature * of the returned future. * * @param supplier the function returning the future. * @return the composed future */ default Future eventually(Supplier> supplier) { return eventually(v -> supplier.get()); } /** * Apply a {@code mapper} function on this future.

* * When this future succeeds, the {@code mapper} will be called with the completed value and this mapper * returns a value. This value will complete the future returned by this method call.

* * If the {@code mapper} throws an exception, the returned future will be failed with this exception.

* * When this future fails, the failure will be propagated to the returned future and the {@code mapper} * will not be called. * * @param mapper the mapper function * @return the mapped future */ Future map(Function mapper); /** * Map the result of a future to a specific {@code value}.

* * When this future succeeds, this {@code value} will complete the future returned by this method call.

* * When this future fails, the failure will be propagated to the returned future. * * @param value the value that eventually completes the mapped future * @return the mapped future */ Future map(V value); /** * Map the result of a future to {@code null}.

* * This is a conveniency for {@code future.map((T) null)} or {@code future.map((Void) null)}.

* * When this future succeeds, {@code null} will complete the future returned by this method call.

* * When this future fails, the failure will be propagated to the returned future. * * @return the mapped future */ @Override default Future mapEmpty() { return (Future) AsyncResult.super.mapEmpty(); } /** * Apply a {@code mapper} function on this future.

* * When this future fails, the {@code mapper} will be called with the completed value and this mapper * returns a value. This value will complete the future returned by this method call.

* * If the {@code mapper} throws an exception, the returned future will be failed with this exception.

* * When this future succeeds, the result will be propagated to the returned future and the {@code mapper} * will not be called. * * @param mapper the mapper function * @return the mapped future */ Future otherwise(Function mapper); /** * Map the failure of a future to a specific {@code value}.

* * When this future fails, this {@code value} will complete the future returned by this method call.

* * When this future succeeds, the result will be propagated to the returned future. * * @param value the value that eventually completes the mapped future * @return the mapped future */ Future otherwise(T value); /** * Map the failure of a future to {@code null}.

* * This is a convenience for {@code future.otherwise((T) null)}.

* * When this future fails, the {@code null} value will complete the future returned by this method call.

* * When this future succeeds, the result will be propagated to the returned future. * * @return the mapped future */ default Future otherwiseEmpty() { return (Future) AsyncResult.super.otherwiseEmpty(); } /** * Invokes the given {@code handler} upon completion. *

* If the {@code handler} throws an exception, the returned future will be failed with this exception. * * @param handler invoked upon completion of this future * @return a future completed after the {@code handler} has been invoked */ default Future andThen(Handler> handler) { return transform(ar -> { handler.handle(ar); return (Future) ar; }); } /** * Guard the control flow of this future with an expectation. *

* When the future is completed with a success, the {@code expectation} is called with the result, when the expectation * returns {@code false} the returned future is failed, otherwise the future is completed with the same result. *

* Expectations are usually lambda expressions: *

   * return future.expecting(response -> response.statusCode() == 200);
   * 
* {@link Expectation} instances can also be used: *
   * future = future.expecting(HttpResponseExpectation.SC_OK);
   * 
* * @param expectation the expectation * @return a future succeeded with the result or failed when the expectation returns false */ Future expecting(Expectation expectation); /** * Returns a future succeeded or failed with the outcome of this future when it happens before the timeout fires. When * the timeout fires before, the future is failed with a {@link java.util.concurrent.TimeoutException}, guaranteeing * the returned future to complete within the specified {@code delay}. * * @param delay the delay * @param unit the unit of the delay * @return the timeout future */ Future timeout(long delay, TimeUnit unit); /** * Bridges this Vert.x future to a {@link CompletionStage} instance. *

* The {@link CompletionStage} handling methods will be called from the thread that resolves this future. * * @return a {@link CompletionStage} that completes when this future resolves */ @GenIgnore default CompletionStage toCompletionStage() { CompletableFuture completableFuture = new CompletableFuture<>(); onComplete(ar -> { if (ar.succeeded()) { completableFuture.complete(ar.result()); } else { completableFuture.completeExceptionally(ar.cause()); } }); return completableFuture; } /** * Bridges a {@link CompletionStage} object to a Vert.x future instance. *

* The Vert.x future handling methods will be called from the thread that completes {@code completionStage}. * * @param completionStage a completion stage * @param the result type * @return a Vert.x future that resolves when {@code completionStage} resolves */ @GenIgnore static Future fromCompletionStage(CompletionStage completionStage) { Promise promise = Promise.promise(); completionStage.whenComplete((value, err) -> { if (err != null) { promise.fail(err); } else { promise.complete(value); } }); return promise.future(); } /** * Bridges a {@link CompletionStage} object to a Vert.x future instance. *

* The Vert.x future handling methods will be called on the provided {@code context}. * * @param completionStage a completion stage * @param context a Vert.x context to dispatch to * @param the result type * @return a Vert.x future that resolves when {@code completionStage} resolves */ @GenIgnore static Future fromCompletionStage(CompletionStage completionStage, Context context) { Promise promise = ((ContextInternal) context).promise(); completionStage.whenComplete((value, err) -> { if (err != null) { promise.fail(err); } else { promise.complete(value); } }); return promise.future(); } /** * Park the current thread until the {@code future} is completed, when the future * is completed the thread is un-parked and * *

    *
  • the result value is returned when the future was completed with a result
  • *
  • otherwise, the failure is thrown
  • *
* * This method must be called from a virtual thread. * * @param future the future to await * @return the result * @throws IllegalStateException when called from an event-loop thread or a non Vert.x thread */ static T await(Future future) { io.vertx.core.impl.WorkerExecutor executor = io.vertx.core.impl.WorkerExecutor.unwrapWorkerExecutor(); io.vertx.core.impl.WorkerExecutor.TaskController cont = executor.current(); future.onComplete(ar -> cont.resume()); try { cont.suspendAndAwaitResume(); } catch (InterruptedException e) { Utils.throwAsUnchecked(e); return null; } if (future.succeeded()) { return future.result(); } else { Utils.throwAsUnchecked(future.cause()); return null; } } }