
net.tascalate.concurrent.ConfigurableDependentPromise Maven / Gradle / Ivy
Show all versions of net.tascalate.concurrent Show documentation
/**
* Copyright 2015-2020 Valery Silaev (http://vsilaev.com)
*
* 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 net.tascalate.concurrent;
import static net.tascalate.concurrent.SharedFunctions.cancelPromise;
import static net.tascalate.concurrent.SharedFunctions.iif;
import java.time.Duration;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import net.tascalate.concurrent.core.Delegator;
import net.tascalate.concurrent.decorators.AbstractPromiseDecorator;
/**
*
* {@link DependentPromise} implementation, i.e. concrete wrapper that may keep track origin of this promise
* and cancel them along with this promise itself.
*
* For example:
*
*
* DependentPromise<?> p1 = DependentPromise.from(CallableTask.runAsync(this::someLongRunningMethod, myExecutor));
* DependentPromise<?> p2 = p1.thenRunAsync(this::someOtherLongRunningTask, true);
* ...
* p2.cancel(true);
*
*
*
* In the example p2
is created with specifying p1
as origin (last argument is true
).
* Now when canceling p2
both p2
and p1
will be cancelled if not completed yet.
*
*
The class implements overloads to all composition methods declared in {@link DependentPromise} interface.
*
*
The ones that accepts another {@link CompletionStage} as argument (named *Both*
and
* *Either*
are overloaded with a set of @{link {@link PromiseOrigin} as an argument to let
* you specify what to enlist as origin: "this" related to method call or the parameter.
*
*
Rest of methods from {@link CompletionStage} API are overloaded with boolean argument
* enlistOrigin
that specify whether or not the {@link Promise} object whose
* method is invoiked should be added as an origin to result.
*
*
All methods originally specified in {@link CompletionStage} does not add "this" as an origin to
* resulting promise.
*
* @author vsilaev
*
* @param
* a type of the successfully resolved promise value
*/
public class ConfigurableDependentPromise implements DependentPromise, Delegator {
protected final Promise delegate;
protected final CompletionStage>[] cancellableOrigins;
protected final Set defaultEnlistOptions;
protected ConfigurableDependentPromise(Promise delegate,
Set defaultEnlistOptions,
CompletionStage>[] cancellableOrigins) {
this.delegate = delegate;
this.defaultEnlistOptions = defaultEnlistOptions == null || defaultEnlistOptions.isEmpty() ?
PromiseOrigin.NONE : defaultEnlistOptions;
this.cancellableOrigins = cancellableOrigins;
}
private DependentPromise postConstruct() {
if (isEmptyArray(cancellableOrigins)) {
// Nothing to do
}
if (isCancelled()) {
// Wrapped over already cancelled Promise
// So result.cancel() has no effect
// and we have to cancel origins explicitly
// right after construction
cancelPromises(cancellableOrigins, true);
} else if (isDone()) {
// nothing to do
} else {
delegate.whenComplete((r, e) -> {
if (isCancelled()) {
cancelPromises(cancellableOrigins, true);
}
});
}
return this;
}
public static DependentPromise from(Promise source) {
return from(source, PromiseOrigin.NONE);
}
public static DependentPromise from(Promise source, Set defaultEnlistOptions) {
return doWrap(source, defaultEnlistOptions, null);
}
protected DependentPromise wrap(Promise original, CompletionStage>[] cancellableOrigins) {
return doWrap(original, defaultEnlistOptions, cancellableOrigins);
}
private static DependentPromise doWrap(Promise original,
Set defaultEnlistOptions,
CompletionStage>[] cancellableOrigins) {
if (isEmptyArray(cancellableOrigins)) {
// Nothing to enlist additionally for this "original" instance
if (original instanceof ConfigurableDependentPromise) {
ConfigurableDependentPromise ioriginal = (ConfigurableDependentPromise)original;
if (identicalSets(ioriginal.defaultEnlistOptions, defaultEnlistOptions)) {
// Same defaultEnlistOptions, may reuse
return ioriginal;
}
}
}
return new ConfigurableDependentPromise<>(
original, defaultEnlistOptions, cancellableOrigins
).postConstruct();
}
@Override
public DependentPromise onCancel(Runnable code) {
return new ExtraCancellationDependentPromise<>(this, code).postConstruct();
}
// All delay overloads delegate to these methods
@Override
public DependentPromise delay(Duration duration, boolean delayOnError) {
return delay(duration, delayOnError, defaultEnlistOrigin());
}
@Override
public DependentPromise delay(Duration duration, boolean delayOnError, boolean enlistOrigin) {
return wrap(delegate.delay(duration, delayOnError), origin(enlistOrigin));
}
@Override
public DependentPromise orTimeout(Duration duration, boolean cancelOnTimeout) {
return orTimeout(duration, cancelOnTimeout, defaultEnlistOrigin());
}
@Override
public DependentPromise orTimeout(Duration duration, boolean cancelOnTimeout, boolean enlistOrigin) {
return wrap(delegate.orTimeout(duration, cancelOnTimeout), origin(enlistOrigin));
}
@Override
public DependentPromise onTimeout(T value, Duration duration, boolean cancelOnTimeout) {
return onTimeout(value, duration, cancelOnTimeout, defaultEnlistOrigin());
}
@Override
public DependentPromise onTimeout(T value, Duration duration, boolean cancelOnTimeout, boolean enlistOrigin) {
return wrap(delegate.onTimeout(value, duration, cancelOnTimeout), origin(enlistOrigin));
}
// All onTimeout overloads delegate to this method
@Override
public DependentPromise onTimeout(Supplier extends T> supplier, Duration duration, boolean cancelOnTimeout) {
return onTimeout(supplier, duration, cancelOnTimeout, defaultEnlistOrigin());
}
@Override
public DependentPromise onTimeout(Supplier extends T> supplier, Duration duration, boolean cancelOnTimeout, boolean enlistOrigin) {
return wrap(delegate.onTimeout(supplier, duration, cancelOnTimeout), origin(enlistOrigin));
}
@Override
public DependentPromise thenApply(Function super T, ? extends U> fn, boolean enlistOrigin) {
return wrap(delegate.thenApply(fn), origin(enlistOrigin));
}
@Override
public DependentPromise thenApplyAsync(Function super T, ? extends U> fn, boolean enlistOrigin) {
return wrap(delegate.thenApplyAsync(fn), origin(enlistOrigin));
}
@Override
public DependentPromise thenApplyAsync(Function super T, ? extends U> fn, Executor executor, boolean enlistOrigin) {
return wrap(delegate.thenApplyAsync(fn, executor), origin(enlistOrigin));
}
@Override
public DependentPromise thenAccept(Consumer super T> action, boolean enlistOrigin) {
return wrap(delegate.thenAccept(action), origin(enlistOrigin));
}
@Override
public DependentPromise thenAcceptAsync(Consumer super T> action, boolean enlistOrigin) {
return wrap(delegate.thenAcceptAsync(action), origin(enlistOrigin));
}
@Override
public DependentPromise thenAcceptAsync(Consumer super T> action, Executor executor, boolean enlistOrigin) {
return wrap(delegate.thenAcceptAsync(action, executor), origin(enlistOrigin));
}
@Override
public DependentPromise thenRun(Runnable action, boolean enlistOrigin) {
return wrap(delegate.thenRun(action), origin(enlistOrigin));
}
@Override
public DependentPromise thenRunAsync(Runnable action, boolean enlistOrigin) {
return wrap(delegate.thenRunAsync(action), origin(enlistOrigin));
}
@Override
public DependentPromise thenRunAsync(Runnable action, Executor executor, boolean enlistOrigin) {
return wrap(delegate.thenRunAsync(action, executor), origin(enlistOrigin));
}
@Override
public DependentPromise thenCombine(CompletionStage extends U> other,
BiFunction super T, ? super U, ? extends V> fn,
Set enlistOptions) {
return wrap(delegate.thenCombine(other, fn), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise thenCombineAsync(CompletionStage extends U> other,
BiFunction super T, ? super U, ? extends V> fn,
Set enlistOptions) {
return wrap(delegate.thenCombineAsync(other, fn), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise thenCombineAsync(CompletionStage extends U> other,
BiFunction super T, ? super U, ? extends V> fn,
Executor executor,
Set enlistOptions) {
return wrap(delegate.thenCombineAsync(other, fn, executor), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise thenAcceptBoth(CompletionStage extends U> other,
BiConsumer super T, ? super U> action,
Set enlistOptions) {
return wrap(delegate.thenAcceptBoth(other, action), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise thenAcceptBothAsync(CompletionStage extends U> other,
BiConsumer super T, ? super U> action,
Set enlistOptions) {
return wrap(delegate.thenAcceptBothAsync(other, action), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise thenAcceptBothAsync(CompletionStage extends U> other,
BiConsumer super T, ? super U> action,
Executor executor,
Set enlistOptions) {
return wrap(delegate.thenAcceptBothAsync(other, action, executor), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise runAfterBoth(CompletionStage> other, Runnable action, Set enlistOptions) {
return wrap(delegate.runAfterBoth(other, action), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise runAfterBothAsync(CompletionStage> other, Runnable action, Set enlistOptions) {
return wrap(delegate.runAfterBothAsync(other, action), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise runAfterBothAsync(CompletionStage> other,
Runnable action,
Executor executor,
Set enlistOptions) {
return wrap(delegate.runAfterBothAsync(other, action, executor), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise applyToEither(CompletionStage extends T> other,
Function super T, U> fn,
Set enlistOptions) {
return wrap(delegate.applyToEither(other, fn), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise applyToEitherAsync(CompletionStage extends T> other,
Function super T, U> fn,
Set enlistOptions) {
return wrap(delegate.applyToEitherAsync(other, fn), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise applyToEitherAsync(CompletionStage extends T> other,
Function super T, U> fn,
Executor executor,
Set enlistOptions) {
return wrap(delegate.applyToEitherAsync(other, fn, executor), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise acceptEither(CompletionStage extends T> other,
Consumer super T> action,
Set enlistOptions) {
return wrap(delegate.acceptEither(other, action), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise acceptEitherAsync(CompletionStage extends T> other,
Consumer super T> action,
Set enlistOptions) {
return wrap(delegate.acceptEitherAsync(other, action), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise acceptEitherAsync(CompletionStage extends T> other,
Consumer super T> action,
Executor executor,
Set enlistOptions) {
return wrap(delegate.acceptEitherAsync(other, action, executor), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise runAfterEither(CompletionStage> other, Runnable action, Set enlistOptions) {
return wrap(delegate.runAfterEither(other, action), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise runAfterEitherAsync(CompletionStage> other, Runnable action, Set enlistOptions) {
return wrap(delegate.runAfterEitherAsync(other, action), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise runAfterEitherAsync(CompletionStage> other,
Runnable action,
Executor executor,
Set enlistOptions) {
return wrap(delegate.runAfterEitherAsync(other, action, executor), originAndParam(other, enlistOptions));
}
@Override
public DependentPromise thenCompose(Function super T, ? extends CompletionStage> fn, boolean enlistOrigin) {
return wrap(delegate.thenCompose(fn), origin(enlistOrigin));
}
@Override
public DependentPromise thenComposeAsync(Function super T, ? extends CompletionStage> fn, boolean enlistOrigin) {
return wrap(delegate.thenComposeAsync(fn), origin(enlistOrigin));
}
@Override
public DependentPromise thenComposeAsync(Function super T, ? extends CompletionStage> fn,
Executor executor,
boolean enlistOrigin) {
return wrap(delegate.thenComposeAsync(fn, executor), origin(enlistOrigin));
}
@Override
public DependentPromise exceptionally(Function fn, boolean enlistOrigin) {
return wrap(delegate.exceptionally(fn), origin(enlistOrigin));
}
@Override
public DependentPromise exceptionallyAsync(Function fn, boolean enlistOrigin) {
return wrap(delegate.exceptionallyAsync(fn), origin(enlistOrigin));
}
@Override
public DependentPromise exceptionallyAsync(Function fn, Executor executor, boolean enlistOrigin) {
return wrap(delegate.exceptionallyAsync(fn, executor), origin(enlistOrigin));
}
@Override
public DependentPromise exceptionallyCompose(Function> fn, boolean enlistOrigin) {
return wrap(delegate.exceptionallyCompose(fn), origin(enlistOrigin));
}
@Override
public DependentPromise exceptionallyComposeAsync(Function> fn, boolean enlistOrigin) {
return wrap(delegate.exceptionallyComposeAsync(fn), origin(enlistOrigin));
}
@Override
public DependentPromise exceptionallyComposeAsync(Function> fn,
Executor executor,
boolean enlistOrigin) {
return wrap(delegate.exceptionallyComposeAsync(fn, executor), origin(enlistOrigin));
}
@Override
public DependentPromise thenFilter(Predicate super T> predicate, boolean enlistOrigin) {
return wrap(delegate.thenFilter(predicate), origin(enlistOrigin));
}
@Override
public DependentPromise thenFilter(Predicate super T> predicate, Function super T, Throwable> errorSupplier, boolean enlistOrigin) {
return wrap(delegate.thenFilter(predicate, errorSupplier), origin(enlistOrigin));
}
@Override
public DependentPromise thenFilterAsync(Predicate super T> predicate, boolean enlistOrigin) {
return wrap(delegate.thenFilterAsync(predicate), origin(enlistOrigin));
}
@Override
public DependentPromise thenFilterAsync(Predicate super T> predicate, Function super T, Throwable> errorSupplier, boolean enlistOrigin) {
return wrap(delegate.thenFilterAsync(predicate, errorSupplier), origin(enlistOrigin));
}
@Override
public DependentPromise thenFilterAsync(Predicate super T> predicate, Executor executor, boolean enlistOrigin) {
return wrap(delegate.thenFilterAsync(predicate, executor), origin(enlistOrigin));
}
@Override
public DependentPromise thenFilterAsync(Predicate super T> predicate, Function super T, Throwable> errorSupplier, Executor executor, boolean enlistOrigin) {
return wrap(delegate.thenFilterAsync(predicate, errorSupplier, executor), origin(enlistOrigin));
}
@Override
public DependentPromise whenComplete(BiConsumer super T, ? super Throwable> action, boolean enlistOrigin) {
return wrap(delegate.whenComplete(action), origin(enlistOrigin));
}
@Override
public DependentPromise whenCompleteAsync(BiConsumer super T, ? super Throwable> action, boolean enlistOrigin) {
return wrap(delegate.whenCompleteAsync(action), origin(enlistOrigin));
}
@Override
public DependentPromise whenCompleteAsync(BiConsumer super T, ? super Throwable> action,
Executor executor,
boolean enlistOrigin) {
return wrap(delegate.whenCompleteAsync(action, executor), origin(enlistOrigin));
}
@Override
public DependentPromise handle(BiFunction super T, Throwable, ? extends U> fn, boolean enlistOrigin) {
return wrap(delegate.handle(fn), origin(enlistOrigin));
}
@Override
public DependentPromise handleAsync(BiFunction super T, Throwable, ? extends U> fn, boolean enlistOrigin) {
return wrap(delegate.handleAsync(fn), origin(enlistOrigin));
}
@Override
public DependentPromise handleAsync(BiFunction super T, Throwable, ? extends U> fn,
Executor executor,
boolean enlistOrigin) {
return wrap(delegate.handleAsync(fn, executor), origin(enlistOrigin));
}
@Override
public DependentPromise thenApply(Function super T, ? extends U> fn) {
return thenApply(fn, defaultEnlistOrigin());
}
@Override
public DependentPromise thenApplyAsync(Function super T, ? extends U> fn) {
return thenApplyAsync(fn, defaultEnlistOrigin());
}
@Override
public DependentPromise thenApplyAsync(Function super T, ? extends U> fn, Executor executor) {
return thenApplyAsync(fn, executor, defaultEnlistOrigin());
}
@Override
public DependentPromise thenAccept(Consumer super T> action) {
return thenAccept(action, defaultEnlistOrigin());
}
@Override
public DependentPromise thenAcceptAsync(Consumer super T> action) {
return thenAcceptAsync(action, defaultEnlistOrigin());
}
@Override
public DependentPromise thenAcceptAsync(Consumer super T> action, Executor executor) {
return thenAcceptAsync(action, executor, defaultEnlistOrigin());
}
@Override
public DependentPromise thenRun(Runnable action) {
return thenRun(action, defaultEnlistOrigin());
}
@Override
public DependentPromise thenRunAsync(Runnable action) {
return thenRunAsync(action, defaultEnlistOrigin());
}
@Override
public DependentPromise thenRunAsync(Runnable action, Executor executor) {
return thenRunAsync(action, executor, defaultEnlistOrigin());
}
@Override
public DependentPromise thenCombine(CompletionStage extends U> other,
BiFunction super T, ? super U, ? extends V> fn) {
return thenCombine(other, fn, defaultEnlistOptions);
}
@Override
public DependentPromise thenCombineAsync(CompletionStage extends U> other,
BiFunction super T, ? super U, ? extends V> fn) {
return thenCombineAsync(other, fn, defaultEnlistOptions);
}
@Override
public DependentPromise thenCombineAsync(CompletionStage extends U> other,
BiFunction super T, ? super U, ? extends V> fn,
Executor executor) {
return thenCombineAsync(other, fn, executor, defaultEnlistOptions);
}
@Override
public DependentPromise thenAcceptBoth(CompletionStage extends U> other,
BiConsumer super T, ? super U> action) {
return thenAcceptBoth(other, action, defaultEnlistOptions);
}
@Override
public DependentPromise thenAcceptBothAsync(CompletionStage extends U> other,
BiConsumer super T, ? super U> action) {
return thenAcceptBothAsync(other, action, defaultEnlistOptions);
}
@Override
public DependentPromise thenAcceptBothAsync(CompletionStage extends U> other,
BiConsumer super T, ? super U> action,
Executor executor) {
return thenAcceptBothAsync(other, action, executor, defaultEnlistOptions);
}
@Override
public DependentPromise runAfterBoth(CompletionStage> other, Runnable action) {
return runAfterBoth(other, action, defaultEnlistOptions);
}
@Override
public DependentPromise runAfterBothAsync(CompletionStage> other, Runnable action) {
return runAfterBothAsync(other, action, defaultEnlistOptions);
}
@Override
public DependentPromise runAfterBothAsync(CompletionStage> other,
Runnable action,
Executor executor) {
return runAfterBothAsync(other, action, executor, defaultEnlistOptions);
}
@Override
public DependentPromise applyToEither(CompletionStage extends T> other, Function super T, U> fn) {
return applyToEither(other, fn, defaultEnlistOptions);
}
@Override
public DependentPromise applyToEitherAsync(CompletionStage extends T> other, Function super T, U> fn) {
return applyToEitherAsync(other, fn, defaultEnlistOptions);
}
@Override
public DependentPromise applyToEitherAsync(CompletionStage extends T> other,
Function super T, U> fn,
Executor executor) {
return applyToEitherAsync(other, fn, executor, defaultEnlistOptions);
}
@Override
public DependentPromise acceptEither(CompletionStage extends T> other, Consumer super T> action) {
return acceptEither(other, action, defaultEnlistOptions);
}
@Override
public DependentPromise acceptEitherAsync(CompletionStage extends T> other, Consumer super T> action) {
return acceptEitherAsync(other, action, defaultEnlistOptions);
}
@Override
public DependentPromise acceptEitherAsync(CompletionStage extends T> other,
Consumer super T> action,
Executor executor) {
return acceptEitherAsync(other, action, executor, defaultEnlistOptions);
}
@Override
public DependentPromise runAfterEither(CompletionStage> other, Runnable action) {
return runAfterEither(other, action, defaultEnlistOptions);
}
@Override
public DependentPromise runAfterEitherAsync(CompletionStage> other, Runnable action) {
return runAfterEitherAsync(other, action, defaultEnlistOptions);
}
@Override
public DependentPromise runAfterEitherAsync(CompletionStage> other,
Runnable action,
Executor executor) {
return runAfterEitherAsync(other, action, executor, defaultEnlistOptions);
}
@Override
public DependentPromise thenCompose(Function super T, ? extends CompletionStage> fn) {
return thenCompose(fn, defaultEnlistOrigin());
}
@Override
public DependentPromise thenComposeAsync(Function super T, ? extends CompletionStage> fn) {
return thenComposeAsync(fn, defaultEnlistOrigin());
}
@Override
public DependentPromise thenComposeAsync(Function super T, ? extends CompletionStage> fn, Executor executor) {
return thenComposeAsync(fn, executor, defaultEnlistOrigin());
}
@Override
public DependentPromise exceptionally(Function fn) {
return exceptionally(fn, defaultEnlistOrigin());
}
@Override
public DependentPromise exceptionallyAsync(Function fn) {
return exceptionallyAsync(fn, defaultEnlistOrigin());
}
@Override
public DependentPromise exceptionallyCompose(Function> fn) {
return exceptionallyCompose(fn, defaultEnlistOrigin());
}
@Override
public DependentPromise exceptionallyComposeAsync(Function> fn) {
return exceptionallyComposeAsync(fn, defaultEnlistOrigin());
}
@Override
public DependentPromise exceptionallyComposeAsync(Function> fn, Executor executor) {
return exceptionallyComposeAsync(fn, executor, defaultEnlistOrigin());
}
@Override
public DependentPromise exceptionallyAsync(Function fn, Executor executor) {
return exceptionallyAsync(fn, executor, defaultEnlistOrigin());
}
@Override
public DependentPromise thenFilter(Predicate super T> predicate) {
return thenFilter(predicate, defaultEnlistOrigin());
}
@Override
public DependentPromise thenFilter(Predicate super T> predicate, Function super T, Throwable> errorSupplier) {
return thenFilter(predicate, errorSupplier, defaultEnlistOrigin());
}
@Override
public DependentPromise thenFilterAsync(Predicate super T> predicate) {
return thenFilterAsync(predicate, defaultEnlistOrigin());
}
@Override
public DependentPromise thenFilterAsync(Predicate super T> predicate, Function super T, Throwable> errorSupplier) {
return thenFilterAsync(predicate, errorSupplier, defaultEnlistOrigin());
}
@Override
public DependentPromise thenFilterAsync(Predicate super T> predicate, Executor executor) {
return thenFilterAsync(predicate, executor, defaultEnlistOrigin());
}
@Override
public DependentPromise thenFilterAsync(Predicate super T> predicate, Function super T, Throwable> errorSupplier, Executor executor) {
return thenFilterAsync(predicate, errorSupplier, executor, defaultEnlistOrigin());
}
@Override
public DependentPromise whenComplete(BiConsumer super T, ? super Throwable> action) {
return whenComplete(action, defaultEnlistOrigin());
}
@Override
public DependentPromise whenCompleteAsync(BiConsumer super T, ? super Throwable> action) {
return whenCompleteAsync(action, defaultEnlistOrigin());
}
@Override
public DependentPromise whenCompleteAsync(BiConsumer super T, ? super Throwable> action, Executor executor) {
return whenCompleteAsync(action, executor, defaultEnlistOrigin());
}
@Override
public DependentPromise handle(BiFunction super T, Throwable, ? extends U> fn) {
return handle(fn, defaultEnlistOrigin());
}
@Override
public DependentPromise handleAsync(BiFunction super T, Throwable, ? extends U> fn) {
return handleAsync(fn, defaultEnlistOrigin());
}
@Override
public DependentPromise handleAsync(BiFunction super T, Throwable, ? extends U> fn, Executor executor) {
return handleAsync(fn, executor, defaultEnlistOrigin());
}
@Override
public DependentPromise dependent() {
return dependent(PromiseOrigin.NONE);
}
@Override
public DependentPromise dependent(Set defaultEnlistOptions) {
if (null == defaultEnlistOptions) {
defaultEnlistOptions = PromiseOrigin.NONE;
}
if (identicalSets(defaultEnlistOptions, this.defaultEnlistOptions)) {
return this;
} else {
return ConfigurableDependentPromise.from(
null == cancellableOrigins || cancellableOrigins.length == 0 ? delegate : cancellablePromiseOf(delegate),
defaultEnlistOptions
);
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
// See postConstruct -- handling is done in delegate.whenComplete
return delegate.cancel(mayInterruptIfRunning);
}
@Override
public boolean isCancelled() {
return delegate.isCancelled();
}
@Override
public boolean isDone() {
return delegate.isDone();
}
@Override
public T get() throws InterruptedException, ExecutionException {
return delegate.get();
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return delegate.get(timeout, unit);
}
@Override
public T getNow(T valueIfAbsent) throws CancellationException, CompletionException {
return delegate.getNow(valueIfAbsent);
}
@Override
public T getNow(Supplier extends T> valueIfAbsent) throws CancellationException, CompletionException {
return delegate.getNow(valueIfAbsent);
}
@Override
public T join() throws CancellationException, CompletionException {
return delegate.join();
}
@Override
public boolean isCompletedExceptionally() {
return delegate.isCompletedExceptionally();
}
@Override
public Promise unwrap() {
if (null == cancellableOrigins || cancellableOrigins.length == 0) {
// No state collected, may optimize away own reference
return delegate;
} else {
return cancellablePromiseOf(delegate);
}
}
@Override
public Promise raw() {
if (null == cancellableOrigins || cancellableOrigins.length == 0) {
// No state collected, may optimize away own reference
return delegate.raw();
} else {
return cancellablePromiseOf(delegate.raw());
}
}
protected Promise cancellablePromiseOf(Promise original) {
return new UndecoratedCancellationPromise<>(original, cancellableOrigins);
}
@Override
public CompletableFuture toCompletableFuture() {
return toCompletableFuture(defaultEnlistOrigin());
}
@Override
public CompletableFuture toCompletableFuture(boolean enlistOrigin) {
CompletionStage alpha = alphaOf(delegate);
CompletableFuture rootDelegate = alpha instanceof CompletableFuture ? (CompletableFuture)alpha : null;
CompletableFuture result;
if (enlistOrigin) {
if (rootDelegate != null) {
// Use toCompletableFuture only if there is a delegate
CompletableFuture defaultResult = delegate.toCompletableFuture();
if (rootDelegate == defaultResult) {
return defaultResult;
}
}
result = new CompletableFuture() {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
ConfigurableDependentPromise.this.cancel(mayInterruptIfRunning);
return super.cancel(mayInterruptIfRunning);
}
};
} else {
CompletableFuture defaultResult = delegate.toCompletableFuture();
if (rootDelegate != defaultResult) {
// Assume if there is no rootDelegate or rootDelegate != rootDelegate.toCompletableFuture
// then toCompletableFuture returns stage that doesn't cancel original one
return defaultResult;
}
result = new CompletableFuture<>();
}
whenComplete((r, e) -> iif(null == e ? result.complete(r) : result.completeExceptionally(e)));
return result;
}
@Override
public CompletionStage α() {
return alphaOf(delegate);
}
@Override
public String toString() {
return String.format(
"%s@%d[delegate=%s, enlistOptions=%s, cancellable=%s]",
getClass().getSimpleName(), System.identityHashCode(this),
delegate, this.defaultEnlistOptions, null == cancellableOrigins ? "{}" : Arrays.asList(cancellableOrigins)
);
}
private static CompletionStage alphaOf(Promise promise) {
if (promise instanceof Delegator) {
@SuppressWarnings("unchecked")
Delegator delegator = (Delegator)promise;
return delegator.α();
} else {
return promise;
}
}
private CompletionStage>[] origin(boolean enlist) {
if (enlist) {
CompletionStage>[] result = new CompletionStage>[1];
result[0] = this;
return result;
} else {
return null;
}
}
private CompletionStage>[] originAndParam(CompletionStage> param, Set enlistOptions) {
final CompletionStage>[] result = new CompletionStage>[enlistOptions.size()];
int idx = 0;
if (enlistOptions.contains(PromiseOrigin.THIS)) {
result[idx++] = this;
}
if (enlistOptions.contains(PromiseOrigin.PARAM) && param != null) {
result[idx++] = param;
}
return result;
}
private boolean defaultEnlistOrigin() {
return defaultEnlistOptions.contains(PromiseOrigin.THIS);
}
static void cancelPromises(CompletionStage>[] promises, boolean mayInterruptIfRunning) {
if (!isEmptyArray(promises)) {
Arrays.stream(promises)
.filter(p -> p != null)
.forEach(p -> cancelPromise(p, mayInterruptIfRunning));
}
}
private static boolean identicalSets(Set> a, Set> b) {
return a.containsAll(b) && b.containsAll(a);
}
private static boolean isEmptyArray(Object[] array) {
return null == array || array.length == 0;
}
static class UndecoratedCancellationPromise extends AbstractPromiseDecorator> {
private final CompletionStage>[] dependent;
UndecoratedCancellationPromise(Promise original, CompletionStage>[] dependent) {
super(original);
this.dependent = dependent;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (super.cancel(mayInterruptIfRunning)) {
cancelPromises(dependent, mayInterruptIfRunning);
return true;
} else {
return false;
}
}
@Override
public Promise unwrap() {
return unwrap(Promise::unwrap);
}
@Override
public Promise raw() {
return unwrap(Promise::raw);
}
private Promise unwrap(Function, Promise> fn) {
Promise unwrapped = fn.apply(delegate);
if (unwrapped == delegate) {
return this;
} else {
return new UndecoratedCancellationPromise<>(unwrapped, dependent);
}
}
@Override
protected Promise wrap(CompletionStage original) {
// No wrapping by definition
return (Promise)original;
}
}
}