/* * Copyright (c) 2011-2013 The original author or authors * ------------------------------------------------------ * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Apache License v2.0 is available at * http://www.opensource.org/licenses/apache2.0.php * * You may elect to redistribute this code under either of these licenses. */ package io.vertx.core; import io.vertx.codegen.annotations.CacheReturn; import io.vertx.codegen.annotations.Fluent; import io.vertx.codegen.annotations.GenIgnore; import io.vertx.codegen.annotations.VertxGen; import io.vertx.core.spi.FutureFactory; import java.util.function.Function; /** * Represents the result of an action that may, or may not, have occurred yet. * <p> * * @author <a href="http://tfox.org">Tim Fox</a> */ @VertxGen public interface Future<T> extends AsyncResult<T>, Handler<AsyncResult<T>> { /** * 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 <T> the result type * @return the future. */ static <T> Future<T> future(Handler<Future<T>> handler) { Future<T> fut = future(); handler.handle(fut); return fut; } /** * Create a future that hasn't completed yet * * @param <T> the result type * @return the future */ static <T> Future<T> future() { return factory.future(); } /** * Create a succeeded future with a null result * * @param <T> the result type * @return the future */ static <T> Future<T> succeededFuture() { return factory.succeededFuture(); } /** * Created a succeeded future with the specified result. * * @param result the result * @param <T> the result type * @return the future */ static <T> Future<T> succeededFuture(T result) { return factory.succeededFuture(result); } /** * Create a failed future with the specified failure cause. * * @param t the failure cause as a Throwable * @param <T> the result type * @return the future */ static <T> Future<T> failedFuture(Throwable t) { return factory.failedFuture(t); } /** * Create a failed future with the specified failure message. * * @param failureMessage the failure message * @param <T> the result type * @return the future */ static <T> Future<T> failedFuture(String failureMessage) { return factory.failureFuture(failureMessage); } /** * Has the future completed? * <p> * It's completed if it's either succeeded or failed. * * @return true if completed, false if not */ boolean isComplete(); /** * Set a handler for the result. * <p> * If the future has already been completed it will be called immediately. Otherwise it will be called when the * future is completed. * * @param handler the Handler that will be called with the result * @return a reference to this, so it can be used fluently * */ @Fluent Future<T> setHandler(Handler<AsyncResult<T>> handler); /** * Set the result. Any handler will be called, if there is one, and the future will be marked as completed. * * @param result the result */ void complete(T result); /** * Set a null result. Any handler will be called, if there is one, and the future will be marked as completed. */ void complete(); /** * Set the failure. Any handler will be called, if there is one, and the future will be marked as completed. * * @param cause the failure cause */ void fail(Throwable cause); /** * Try to set the failure. When it happens, any handler will be called, if there is one, and the future will be marked as completed. * * @param failureMessage the failure message */ void fail(String failureMessage); /** * Set the failure. Any handler will be called, if there is one, and the future will be marked as completed. * * @param result the result * @return false when the future is already completed */ boolean tryComplete(T result); /** * Try to set the result. When it happens, any handler will be called, if there is one, and the future will be marked as completed. * * @return false when the future is already completed */ boolean tryComplete(); /** * Try to set the failure. When it happens, any handler will be called, if there is one, and the future will be marked as completed. * * @param cause the failure cause * @return false when the future is already completed */ boolean tryFail(Throwable cause); /** * Try to set the failure. When it happens, any handler will be called, if there is one, and the future will be marked as completed. * * @param failureMessage the failure message * @return false when the future is already completed */ boolean tryFail(String failureMessage); /** * 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(); /** * Compose this future with a provided {@code next} future.<p> * * When this (the one on which {@code compose} is called) future succeeds, the {@code handler} will be called with * the completed value, this handler should complete the next future.<p> * * If the {@code handler} throws an exception, the returned future will be failed with this exception.<p> * * When this future fails, the failure will be propagated to the {@code next} future and the {@code handler} * will not be called. * * @param handler the handler * @param next the next future * @return the next future, used for chaining */ default <U> Future<U> compose(Handler<T> handler, Future<U> next) { setHandler(ar -> { if (ar.succeeded()) { try { handler.handle(ar.result()); } catch (Throwable err) { if (next.isComplete()) { throw err; } next.fail(err); } } else { next.fail(ar.cause()); } }); return next; } /** * Compose this future with a {@code mapper} function.<p> * * 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.<p> * * If the {@code mapper} throws an exception, the returned future will be failed with this exception.<p> * * 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 <U> Future<U> compose(Function<T, Future<U>> mapper) { if (mapper == null) { throw new NullPointerException(); } Future<U> ret = Future.future(); setHandler(ar -> { if (ar.succeeded()) { Future<U> apply; try { apply = mapper.apply(ar.result()); } catch (Throwable e) { ret.fail(e); return; } apply.setHandler(ret); } else { ret.fail(ar.cause()); } }); return ret; } /** * Apply a {@code mapper} function on this future.<p> * * 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.<p> * * If the {@code mapper} throws an exception, the returned future will be failed with this exception.<p> * * 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 */ default <U> Future<U> map(Function<T, U> mapper) { if (mapper == null) { throw new NullPointerException(); } Future<U> ret = Future.future(); setHandler(ar -> { if (ar.succeeded()) { U mapped; try { mapped = mapper.apply(ar.result()); } catch (Throwable e) { ret.fail(e); return; } ret.complete(mapped); } else { ret.fail(ar.cause()); } }); return ret; } /** * Map the result of a future to a specific {@code value}.<p> * * When this future succeeds, this {@code value} will complete the future returned by this method call.<p> * * 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 */ default <V> Future<V> map(V value) { Future<V> ret = Future.future(); setHandler(ar -> { if (ar.succeeded()) { ret.complete(value); } else { ret.fail(ar.cause()); } }); return ret; } /** * Map the result of a future to {@code null}.<p> * * This is a conveniency for {@code future.map((T) null)} or {@code future.map((Void) null)}.<p> * * When this future succeeds, {@code null} will complete the future returned by this method call.<p> * * When this future fails, the failure will be propagated to the returned future. * * @return the mapped future */ @Override default <V> Future<V> mapEmpty() { return (Future<V>) AsyncResult.super.mapEmpty(); } /** * Succeed or fail this future with the {@link AsyncResult} event. * * @param asyncResult the async result to handle */ @GenIgnore @Override void handle(AsyncResult<T> asyncResult); /** * @return an handler completing this future */ @CacheReturn default Handler<AsyncResult<T>> completer() { return this; } /** * 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<T> recover(Function<Throwable, Future<T>> mapper) { if (mapper == null) { throw new NullPointerException(); } Future<T> ret = Future.future(); setHandler(ar -> { if (ar.succeeded()) { ret.complete(result()); } else { Future<T> mapped; try { mapped = mapper.apply(ar.cause()); } catch (Throwable e) { ret.fail(e); return; } mapped.setHandler(ret); } }); return ret; } /** * Apply a {@code mapper} function on this future.<p> * * 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.<p> * * If the {@code mapper} throws an exception, the returned future will be failed with this exception.<p> * * 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 */ default Future<T> otherwise(Function<Throwable, T> mapper) { if (mapper == null) { throw new NullPointerException(); } Future<T> ret = Future.future(); setHandler(ar -> { if (ar.succeeded()) { ret.complete(result()); } else { T value; try { value = mapper.apply(ar.cause()); } catch (Throwable e) { ret.fail(e); return; } ret.complete(value); } }); return ret; } /** * Map the failure of a future to a specific {@code value}.<p> * * When this future fails, this {@code value} will complete the future returned by this method call.<p> * * 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 */ default Future<T> otherwise(T value) { Future<T> ret = Future.future(); setHandler(ar -> { if (ar.succeeded()) { ret.complete(result()); } else { ret.complete(value); } }); return ret; } /** * Map the failure of a future to {@code null}.<p> * * This is a convenience for {@code future.otherwise((T) null)}.<p> * * When this future fails, the {@code null} value will complete the future returned by this method call.<p> * * When this future succeeds, the result will be propagated to the returned future. * * @return the mapped future */ default Future<T> otherwiseEmpty() { return (Future<T>) AsyncResult.super.otherwiseEmpty(); } FutureFactory factory = ServiceHelper.loadFactory(FutureFactory.class); }