/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/.ɪᴏ
* ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
*/
package io.vavr.concurrent;
import io.vavr.control.Try;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import static io.vavr.concurrent.Future.DEFAULT_EXECUTOR_SERVICE;
/**
* A Promise is a write-once wrapper around a read-only Future which can complete the underlying Future with a value
* or an exception.
* <p>
* The underlying {@code ExecutorService} is used to execute asynchronous handlers, e.g. via
* {@code promise.future().onComplete(...)}.
*
* <h3>Creation</h3>
* <p>
* Promise offers static factory methods to create new promises which hasn't been fulfilled yet:
* <ul>
* <li>create new promises: {@link Promise#make()}</li>
* </ul>
* And we may create new promises that are already finished:
* <ul>
* <li>{@link #failed(Throwable)}</li>
* <li>{@link #fromTry(Try)}</li>
* <li>{@link #successful(Object)}</li>
* </ul>
* All the static factory methods mentioned above have additional versions which take an {@link ExecutorService} as
* argument. This gives us more control over thread creation and thread pool sizes.
*
* <h3>One-shot API</h3>
* <p>
* The main purpose of a {@code Promise} is to complete its underlying {@code Future}. When only a single {@code Thread}
* will eventually complete the {@code Promise}, we use one of these methods. Calls will throw if the {@code Promise} is already
* completed.
* <ul>
* <li>{@link #complete(Try)}</li>
* <li>{@link #completeWith(Future)}</li>
* <li>{@link #failure(Throwable)}</li>
* <li>{@link #success(Object)}</li>
* </ul>
*
* <h3>API for competing threads</h3>
* <p>
* When multiple {@code Thread}s may complete our {@code Promise}, we typically use one of these methods. Calls will
* gracefully return {@code false} if the {@code Promise} is already completed.
* <ul>
* <li>{@link #tryComplete(Try)}</li>
* <li>{@link #tryCompleteWith(Future)}</li>
* <li>{@link #tryFailure(Throwable)}</li>
* <li>{@link #trySuccess(Object)}</li>
* </ul>
*
* @param <T> The result type of the underlying {@code Future}.
* @author Daniel Dietrich
*/
public interface Promise<T> {
/**
* Creates a failed {@code Promise}, backed by the {@link Future#DEFAULT_EXECUTOR_SERVICE}.
*
* @param exception The reason why it failed.
* @param <T> The value type of a successful result.
* @return A failed {@code Promise}.
* @throws NullPointerException if exception is null
*/
static <T> Promise<T> failed(Throwable exception) {
Objects.requireNonNull(exception, "exception is null");
return failed(DEFAULT_EXECUTOR_SERVICE, exception);
}
/**
* Creates a failed {@code Promise}, backed by the given {@link ExecutorService}.
*
* @param executorService An {@code ExecutorService} passed to the underlying {@link Future}.
* @param exception The reason why it failed.
* @param <T> The value type of a successful result.
* @return A failed {@code Promise}.
* @throws NullPointerException if executorService or exception is null
*/
static <T> Promise<T> failed(ExecutorService executorService, Throwable exception) {
Objects.requireNonNull(executorService, "executorService is null");
Objects.requireNonNull(exception, "exception is null");
return Promise.<T> make(executorService).failure(exception);
}
/**
* Creates a {@code Promise} from a {@link Try}, backed by the {@link Future#DEFAULT_EXECUTOR_SERVICE}.
*
* @param result The result.
* @param <T> The value type of a successful result.
* @return A completed {@code Promise} which contains either a {@code Success} or a {@code Failure}.
* @throws NullPointerException if result is null
*/
static <T> Promise<T> fromTry(Try<? extends T> result) {
return fromTry(DEFAULT_EXECUTOR_SERVICE, result);
}
/**
* Creates a {@code Promise} from a {@link Try}, backed by the given {@link ExecutorService}.
*
* @param executorService An {@code ExecutorService} passed to the underlying {@link Future}.
* @param result The result.
* @param <T> The value type of a successful result.
* @return A completed {@code Promise} which contains either a {@code Success} or a {@code Failure}.
* @throws NullPointerException if executorService or result is null
*/
static <T> Promise<T> fromTry(ExecutorService executorService, Try<? extends T> result) {
Objects.requireNonNull(executorService, "executorService is null");
Objects.requireNonNull(result, "result is null");
return Promise.<T> make(executorService).complete(result);
}
/**
* Makes a {@code Promise} that isn't fulfilled yet, backed by the {@link Future#DEFAULT_EXECUTOR_SERVICE}.
* {@link ForkJoinPool#commonPool()}.
*
* @param <T> Result type of the {@code Promise}.
* @return A new {@code Promise}.
*/
static <T> Promise<T> make() {
return make(DEFAULT_EXECUTOR_SERVICE);
}
/**
* Makes a {@code Promise} that isn't fulfilled yet, backed by the given {@link ExecutorService}.
*
* @param executorService An {@code ExecutorService} passed to the underlying {@link Future}.
* @param <T> Result type of the {@code Promise}.
* @return A new {@code Promise}.
* @throws NullPointerException if executorService is null
*/
static <T> Promise<T> make(ExecutorService executorService) {
Objects.requireNonNull(executorService, "executorService is null");
return new PromiseImpl<>(new FutureImpl<>(executorService));
}
/**
* Narrows a widened {@code Promise<? extends T>} to {@code Promise<T>}
* by performing a type-safe cast. This is eligible because immutable/read-only
* collections are covariant.
*
* @param promise A {@code Promise}.
* @param <T> Component type of the {@code Promise}.
* @return the given {@code promise} instance as narrowed type {@code Promise<T>}.
*/
@SuppressWarnings("unchecked")
static <T> Promise<T> narrow(Promise<? extends T> promise) {
return (Promise<T>) promise;
}
/**
* Creates a succeeded {@code Promise}, backed by the {@link Future#DEFAULT_EXECUTOR_SERVICE}.
*
* @param result The result.
* @param <T> The value type of a successful result.
* @return A succeeded {@code Promise}.
*/
static <T> Promise<T> successful(T result) {
return successful(DEFAULT_EXECUTOR_SERVICE, result);
}
/**
* Creates a succeeded {@code Promise}, backed by the given {@link ExecutorService}.
*
* @param executorService An {@code ExecutorService} passed to the underlying {@link Future}.
* @param result The result.
* @param <T> The value type of a successful result.
* @return A succeeded {@code Promise}.
* @throws NullPointerException if executorService is null
*/
static <T> Promise<T> successful(ExecutorService executorService, T result) {
Objects.requireNonNull(executorService, "executorService is null");
return Promise.<T> make(executorService).success(result);
}
/**
* Returns the {@link ExecutorService} used by this {@code Future}.
*
* @return The underlying {@code ExecutorService}.
*/
ExecutorService executorService();
/**
* Returns the underlying {@link Future} of this {@code Promise}.
*
* @return The {@code Future}.
*/
Future<T> future();
/**
* Checks if this {@code Promise} is completed, i.e. has a value.
*
* @return true, if the computation successfully finished or failed, false otherwise.
*/
default boolean isCompleted() {
return future().isCompleted();
}
/**
* Completes this {@code Promise} with the given {@code value}.
*
* @param value Either a {@link Try.Success} containing the result or a {@link Try.Failure} containing an exception.
* @return This {@code Promise}.
* @throws IllegalStateException if this {@code Promise} has already been completed.
*/
default Promise<T> complete(Try<? extends T> value) {
if (tryComplete(value)) {
return this;
} else {
throw new IllegalStateException("Promise already completed.");
}
}
/**
* Attempts to completes this {@code Promise} with the given {@code value}.
*
* @param value Either a {@link Try.Success} containing the result or a {@link Try.Failure} containing an exception.
* @return {@code false} if this {@code Promise} has already been completed, {@code true} otherwise.
* @throws IllegalStateException if this {@code Promise} has already been completed.
*/
boolean tryComplete(Try<? extends T> value);
/**
* Completes this {@code Promise} with the given {@code Future}, once that {@code Future} is completed.
*
* @param other Another {@code Future} to react on.
* @return This {@code Promise}.
*/
default Promise<T> completeWith(Future<? extends T> other) {
return tryCompleteWith(other);
}
/**
* Attempts to complete this {@code Promise} with the specified {@code Future}, once that {@code Future} is completed.
*
* @param other Another {@code Future} to react on.
* @return This {@code Promise}.
*/
default Promise<T> tryCompleteWith(Future<? extends T> other) {
other.onComplete(this::tryComplete);
return this;
}
/**
* Completes this {@code Promise} with the given {@code value}.
*
* @param value A value.
* @return This {@code Promise}.
* @throws IllegalStateException if this {@code Promise} has already been completed.
*/
default Promise<T> success(T value) {
return complete(Try.success(value));
}
/**
* Completes this {@code Promise} with the given {@code value}.
*
* @param value A value.
* @return {@code false} if this {@code Promise} has already been completed, {@code true} otherwise.
*/
default boolean trySuccess(T value) {
return tryComplete(Try.success(value));
}
/**
* Completes this {@code Promise} with the given {@code exception}.
*
* @param exception An exception.
* @return This {@code Promise}.
* @throws IllegalStateException if this {@code Promise} has already been completed.
*/
default Promise<T> failure(Throwable exception) {
return complete(Try.failure(exception));
}
/**
* Completes this {@code Promise} with the given {@code exception}.
*
* @param exception An exception.
* @return {@code false} if this {@code Promise} has already been completed, {@code true} otherwise.
*/
default boolean tryFailure(Throwable exception) {
return tryComplete(Try.failure(exception));
}
}
/**
* Internal {@code Promise} implementation.
*
* @param <T> result type
* @author Daniel Dietrich
*/
final class PromiseImpl<T> implements Promise<T> {
private final FutureImpl<T> future;
PromiseImpl(FutureImpl<T> future) {
this.future = future;
}
@Override
public ExecutorService executorService() {
return future.executorService();
}
@Override
public Future<T> future() {
return future;
}
@Override
public boolean tryComplete(Try<? extends T> value) {
return future.tryComplete(value);
}
// The underlying FutureImpl is MUTABLE and therefore we CANNOT CHANGE DEFAULT equals() and hashCode() behavior.
// See http://stackoverflow.com/questions/4718009/mutable-objects-and-hashcode
@Override
public String toString() {
return "Promise(" + future.getValue().map(String::valueOf).getOrElse("?") + ")";
}
}