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

net.tascalate.concurrent.ConfigurableDependentPromise Maven / Gradle / Ivy

Go to download

Implementation of blocking (IO-Bound) cancellable java.util.concurrent.CompletionStage and related extensions to java.util.concurrent.ExecutorService-s

There is a newer version: 0.9.8
Show newest version
/**
 * 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 supplier, Duration duration, boolean cancelOnTimeout) { return onTimeout(supplier, duration, cancelOnTimeout, defaultEnlistOrigin()); } @Override public DependentPromise onTimeout(Supplier supplier, Duration duration, boolean cancelOnTimeout, boolean enlistOrigin) { return wrap(delegate.onTimeout(supplier, duration, cancelOnTimeout), origin(enlistOrigin)); } @Override public DependentPromise thenApply(Function fn, boolean enlistOrigin) { return wrap(delegate.thenApply(fn), origin(enlistOrigin)); } @Override public DependentPromise thenApplyAsync(Function fn, boolean enlistOrigin) { return wrap(delegate.thenApplyAsync(fn), origin(enlistOrigin)); } @Override public DependentPromise thenApplyAsync(Function fn, Executor executor, boolean enlistOrigin) { return wrap(delegate.thenApplyAsync(fn, executor), origin(enlistOrigin)); } @Override public DependentPromise thenAccept(Consumer action, boolean enlistOrigin) { return wrap(delegate.thenAccept(action), origin(enlistOrigin)); } @Override public DependentPromise thenAcceptAsync(Consumer action, boolean enlistOrigin) { return wrap(delegate.thenAcceptAsync(action), origin(enlistOrigin)); } @Override public DependentPromise thenAcceptAsync(Consumer 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 other, BiFunction fn, Set enlistOptions) { return wrap(delegate.thenCombine(other, fn), originAndParam(other, enlistOptions)); } @Override public DependentPromise thenCombineAsync(CompletionStage other, BiFunction fn, Set enlistOptions) { return wrap(delegate.thenCombineAsync(other, fn), originAndParam(other, enlistOptions)); } @Override public DependentPromise thenCombineAsync(CompletionStage other, BiFunction fn, Executor executor, Set enlistOptions) { return wrap(delegate.thenCombineAsync(other, fn, executor), originAndParam(other, enlistOptions)); } @Override public DependentPromise thenAcceptBoth(CompletionStage other, BiConsumer action, Set enlistOptions) { return wrap(delegate.thenAcceptBoth(other, action), originAndParam(other, enlistOptions)); } @Override public DependentPromise thenAcceptBothAsync(CompletionStage other, BiConsumer action, Set enlistOptions) { return wrap(delegate.thenAcceptBothAsync(other, action), originAndParam(other, enlistOptions)); } @Override public DependentPromise thenAcceptBothAsync(CompletionStage other, BiConsumer 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 other, Function fn, Set enlistOptions) { return wrap(delegate.applyToEither(other, fn), originAndParam(other, enlistOptions)); } @Override public DependentPromise applyToEitherAsync(CompletionStage other, Function fn, Set enlistOptions) { return wrap(delegate.applyToEitherAsync(other, fn), originAndParam(other, enlistOptions)); } @Override public DependentPromise applyToEitherAsync(CompletionStage other, Function fn, Executor executor, Set enlistOptions) { return wrap(delegate.applyToEitherAsync(other, fn, executor), originAndParam(other, enlistOptions)); } @Override public DependentPromise acceptEither(CompletionStage other, Consumer action, Set enlistOptions) { return wrap(delegate.acceptEither(other, action), originAndParam(other, enlistOptions)); } @Override public DependentPromise acceptEitherAsync(CompletionStage other, Consumer action, Set enlistOptions) { return wrap(delegate.acceptEitherAsync(other, action), originAndParam(other, enlistOptions)); } @Override public DependentPromise acceptEitherAsync(CompletionStage other, Consumer 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> fn, boolean enlistOrigin) { return wrap(delegate.thenCompose(fn), origin(enlistOrigin)); } @Override public DependentPromise thenComposeAsync(Function> fn, boolean enlistOrigin) { return wrap(delegate.thenComposeAsync(fn), origin(enlistOrigin)); } @Override public DependentPromise thenComposeAsync(Function> 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 predicate, boolean enlistOrigin) { return wrap(delegate.thenFilter(predicate), origin(enlistOrigin)); } @Override public DependentPromise thenFilter(Predicate predicate, Function errorSupplier, boolean enlistOrigin) { return wrap(delegate.thenFilter(predicate, errorSupplier), origin(enlistOrigin)); } @Override public DependentPromise thenFilterAsync(Predicate predicate, boolean enlistOrigin) { return wrap(delegate.thenFilterAsync(predicate), origin(enlistOrigin)); } @Override public DependentPromise thenFilterAsync(Predicate predicate, Function errorSupplier, boolean enlistOrigin) { return wrap(delegate.thenFilterAsync(predicate, errorSupplier), origin(enlistOrigin)); } @Override public DependentPromise thenFilterAsync(Predicate predicate, Executor executor, boolean enlistOrigin) { return wrap(delegate.thenFilterAsync(predicate, executor), origin(enlistOrigin)); } @Override public DependentPromise thenFilterAsync(Predicate predicate, Function errorSupplier, Executor executor, boolean enlistOrigin) { return wrap(delegate.thenFilterAsync(predicate, errorSupplier, executor), origin(enlistOrigin)); } @Override public DependentPromise whenComplete(BiConsumer action, boolean enlistOrigin) { return wrap(delegate.whenComplete(action), origin(enlistOrigin)); } @Override public DependentPromise whenCompleteAsync(BiConsumer action, boolean enlistOrigin) { return wrap(delegate.whenCompleteAsync(action), origin(enlistOrigin)); } @Override public DependentPromise whenCompleteAsync(BiConsumer action, Executor executor, boolean enlistOrigin) { return wrap(delegate.whenCompleteAsync(action, executor), origin(enlistOrigin)); } @Override public DependentPromise handle(BiFunction fn, boolean enlistOrigin) { return wrap(delegate.handle(fn), origin(enlistOrigin)); } @Override public DependentPromise handleAsync(BiFunction fn, boolean enlistOrigin) { return wrap(delegate.handleAsync(fn), origin(enlistOrigin)); } @Override public DependentPromise handleAsync(BiFunction fn, Executor executor, boolean enlistOrigin) { return wrap(delegate.handleAsync(fn, executor), origin(enlistOrigin)); } @Override public DependentPromise thenApply(Function fn) { return thenApply(fn, defaultEnlistOrigin()); } @Override public DependentPromise thenApplyAsync(Function fn) { return thenApplyAsync(fn, defaultEnlistOrigin()); } @Override public DependentPromise thenApplyAsync(Function fn, Executor executor) { return thenApplyAsync(fn, executor, defaultEnlistOrigin()); } @Override public DependentPromise thenAccept(Consumer action) { return thenAccept(action, defaultEnlistOrigin()); } @Override public DependentPromise thenAcceptAsync(Consumer action) { return thenAcceptAsync(action, defaultEnlistOrigin()); } @Override public DependentPromise thenAcceptAsync(Consumer 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 other, BiFunction fn) { return thenCombine(other, fn, defaultEnlistOptions); } @Override public DependentPromise thenCombineAsync(CompletionStage other, BiFunction fn) { return thenCombineAsync(other, fn, defaultEnlistOptions); } @Override public DependentPromise thenCombineAsync(CompletionStage other, BiFunction fn, Executor executor) { return thenCombineAsync(other, fn, executor, defaultEnlistOptions); } @Override public DependentPromise thenAcceptBoth(CompletionStage other, BiConsumer action) { return thenAcceptBoth(other, action, defaultEnlistOptions); } @Override public DependentPromise thenAcceptBothAsync(CompletionStage other, BiConsumer action) { return thenAcceptBothAsync(other, action, defaultEnlistOptions); } @Override public DependentPromise thenAcceptBothAsync(CompletionStage other, BiConsumer 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 other, Function fn) { return applyToEither(other, fn, defaultEnlistOptions); } @Override public DependentPromise applyToEitherAsync(CompletionStage other, Function fn) { return applyToEitherAsync(other, fn, defaultEnlistOptions); } @Override public DependentPromise applyToEitherAsync(CompletionStage other, Function fn, Executor executor) { return applyToEitherAsync(other, fn, executor, defaultEnlistOptions); } @Override public DependentPromise acceptEither(CompletionStage other, Consumer action) { return acceptEither(other, action, defaultEnlistOptions); } @Override public DependentPromise acceptEitherAsync(CompletionStage other, Consumer action) { return acceptEitherAsync(other, action, defaultEnlistOptions); } @Override public DependentPromise acceptEitherAsync(CompletionStage other, Consumer 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> fn) { return thenCompose(fn, defaultEnlistOrigin()); } @Override public DependentPromise thenComposeAsync(Function> fn) { return thenComposeAsync(fn, defaultEnlistOrigin()); } @Override public DependentPromise thenComposeAsync(Function> 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 predicate) { return thenFilter(predicate, defaultEnlistOrigin()); } @Override public DependentPromise thenFilter(Predicate predicate, Function errorSupplier) { return thenFilter(predicate, errorSupplier, defaultEnlistOrigin()); } @Override public DependentPromise thenFilterAsync(Predicate predicate) { return thenFilterAsync(predicate, defaultEnlistOrigin()); } @Override public DependentPromise thenFilterAsync(Predicate predicate, Function errorSupplier) { return thenFilterAsync(predicate, errorSupplier, defaultEnlistOrigin()); } @Override public DependentPromise thenFilterAsync(Predicate predicate, Executor executor) { return thenFilterAsync(predicate, executor, defaultEnlistOrigin()); } @Override public DependentPromise thenFilterAsync(Predicate predicate, Function errorSupplier, Executor executor) { return thenFilterAsync(predicate, errorSupplier, executor, defaultEnlistOrigin()); } @Override public DependentPromise whenComplete(BiConsumer action) { return whenComplete(action, defaultEnlistOrigin()); } @Override public DependentPromise whenCompleteAsync(BiConsumer action) { return whenCompleteAsync(action, defaultEnlistOrigin()); } @Override public DependentPromise whenCompleteAsync(BiConsumer action, Executor executor) { return whenCompleteAsync(action, executor, defaultEnlistOrigin()); } @Override public DependentPromise handle(BiFunction fn) { return handle(fn, defaultEnlistOrigin()); } @Override public DependentPromise handleAsync(BiFunction fn) { return handleAsync(fn, defaultEnlistOrigin()); } @Override public DependentPromise handleAsync(BiFunction 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 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; } } }