/** * 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.selectFirst; import static net.tascalate.concurrent.SharedFunctions.NO_SUCH_ELEMENT; 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.concurrent.atomic.AtomicReference; 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.decorators.AbstractPromiseDecorator; /** * * <p>{@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: * <pre> * <code> * DependentPromise<?> p1 = DependentPromise.from(CallableTask.runAsync(this::someLongRunningMethod, myExecutor)); * DependentPromise<?> p2 = p1.thenRunAsync(this::someOtherLongRunningTask, true); * ... * p2.cancel(true); * * </code> * </pre> * <p>In the example <code>p2</code> is created with specifying <code>p1</code> as origin (last argument is <code>true</code>). * Now when canceling <code>p2</code> both <code>p2</code> and <code>p1</code> will be cancelled if not completed yet. * * <p>The class implements overloads to all composition methods declared in {@link DependentPromise} interface. * * <p>The ones that accepts another {@link CompletionStage} as argument (named <code>*Both*</code> and * <code>*Either*</code> 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. * * <p>Rest of methods from {@link CompletionStage} API are overloaded with boolean argument * <code>enlistOrigin</code> that specify whether or not the {@link Promise} object whose * method is invoiked should be added as an origin to result. * * <p>All methods originally specified in {@link CompletionStage} does not add "this" as an origin to * resulting promise. * * @author vsilaev * * @param <T> * a type of the successfully resolved promise value */ public class ConfigurableDependentPromise<T> implements DependentPromise<T> { protected final Promise<T> delegate; protected final CompletionStage<?>[] cancellableOrigins; protected final Set<PromiseOrigin> defaultEnlistOptions; protected ConfigurableDependentPromise(Promise<T> delegate, Set<PromiseOrigin> defaultEnlistOptions, CompletionStage<?>[] cancellableOrigins) { this.delegate = delegate; this.defaultEnlistOptions = defaultEnlistOptions == null || defaultEnlistOptions.isEmpty() ? PromiseOrigin.NONE : defaultEnlistOptions; this.cancellableOrigins = cancellableOrigins; } public static <U> DependentPromise<U> from(Promise<U> source) { return from(source, PromiseOrigin.NONE); } public static <U> DependentPromise<U> from(Promise<U> source, Set<PromiseOrigin> defaultEnlistOptions) { return doWrap(source, defaultEnlistOptions, null); } protected <U> DependentPromise<U> wrap(Promise<U> original, CompletionStage<?>[] cancellableOrigins) { return doWrap(original, defaultEnlistOptions, cancellableOrigins); } private static <U> DependentPromise<U> doWrap(Promise<U> original, Set<PromiseOrigin> defaultEnlistOptions, CompletionStage<?>[] cancellableOrigins) { if (null == cancellableOrigins || cancellableOrigins.length == 0) { // Nothing to enlist additionally for this "original" instance if (original instanceof ConfigurableDependentPromise) { ConfigurableDependentPromise<U> ioriginal = (ConfigurableDependentPromise<U>)original; if (identicalSets(ioriginal.defaultEnlistOptions, defaultEnlistOptions)) { // Same defaultEnlistOptions, may reuse return ioriginal; } } } ConfigurableDependentPromise<U> result = new ConfigurableDependentPromise<>(original, defaultEnlistOptions, cancellableOrigins); if (result.isCancelled()) { // Wrapped over already cancelled Promise // So result.cancel() has no effect // and we have to cancel origins explicitly // right after construction cancelPromises(result.cancellableOrigins, true); } return result; } @Override public DependentPromise<T> onCancel(Runnable code) { return new ExtraCancellationDependentPromise<>(this, code); } // All delay overloads delegate to these methods @Override public DependentPromise<T> delay(Duration duration, boolean delayOnError) { return delay(duration, delayOnError, defaultEnlistOrigin()); } @Override public DependentPromise<T> delay(Duration duration, boolean delayOnError, boolean enlistOrigin) { if (!(delayOnError || enlistOrigin)) { // Fast route return thenCompose( v -> thenCombineAsync(Timeouts.delay(duration), selectFirst(), PromiseOrigin.PARAM_ONLY) ); } CompletableFuture<Try<? super T>> delayed = new CompletableFuture<>(); whenComplete(Timeouts.configureDelay(this, delayed, duration, delayOnError)); // Use *Async to execute on default "this" executor return this.thenApply(Try::success, enlistOrigin) .exceptionally(Try::failure, true) .thenCombineAsync(delayed, (u, v) -> u.done(), PromiseOrigin.ALL); } // All orTimeout overloads delegate to these methods @Override public DependentPromise<T> orTimeout(Duration duration, boolean cancelOnTimeout) { return orTimeout(duration, cancelOnTimeout, defaultEnlistOrigin()); } @Override public DependentPromise<T> orTimeout(Duration duration, boolean cancelOnTimeout, boolean enlistOrigin) { Promise<? extends Try<T>> onTimeout = Timeouts.delayed(null, duration); DependentPromise<T> result = this.thenApply(Try::success, enlistOrigin) .exceptionally(Try::failure, true) // Use *Async to execute on default "this" executor .applyToEitherAsync(onTimeout, v -> Try.doneOrTimeout(v, duration), PromiseOrigin.ALL); result.whenComplete(Timeouts.timeoutsCleanup(this, onTimeout, cancelOnTimeout)); return result; } @Override public DependentPromise<T> onTimeout(T value, Duration duration, boolean cancelOnTimeout) { return onTimeout(value, duration, cancelOnTimeout, defaultEnlistOrigin()); } @Override public DependentPromise<T> onTimeout(T value, Duration duration, boolean cancelOnTimeout, boolean enlistOrigin) { Promise<Try<T>> onTimeout = Timeouts.delayed(Try.success(value), duration); DependentPromise<T> result = this.thenApply(Try::success, enlistOrigin) .exceptionally(Try::failure, true) // Use *Async to execute on default "this" executor .applyToEitherAsync(onTimeout, Try::done, PromiseOrigin.ALL); result.whenComplete(Timeouts.timeoutsCleanup(this, onTimeout, cancelOnTimeout)); return result; } // All onTimeout overloads delegate to this method @Override public DependentPromise<T> onTimeout(Supplier<? extends T> supplier, Duration duration, boolean cancelOnTimeout) { return onTimeout(supplier, duration, cancelOnTimeout, defaultEnlistOrigin()); } @Override public DependentPromise<T> onTimeout(Supplier<? extends T> supplier, Duration duration, boolean cancelOnTimeout, boolean enlistOrigin) { // timeout converted to supplier Promise<Supplier<Try<T>>> onTimeout = Timeouts.delayed(Try.with(supplier), duration); DependentPromise<T> result = this.thenApply(Try::success, enlistOrigin) .exceptionally(Try::failure, true) .thenApply(SharedFunctions::supply, true) // Use *Async to execute on default "this" executor .applyToEitherAsync(onTimeout, s -> s.get().done(), PromiseOrigin.ALL); result.whenComplete(Timeouts.timeoutsCleanup(this, onTimeout, cancelOnTimeout)); return result; } public <U> DependentPromise<U> thenApply(Function<? super T, ? extends U> fn, boolean enlistOrigin) { return wrap(delegate.thenApply(fn), origin(enlistOrigin)); } public <U> DependentPromise<U> thenApplyAsync(Function<? super T, ? extends U> fn, boolean enlistOrigin) { return wrap(delegate.thenApplyAsync(fn), origin(enlistOrigin)); } public <U> DependentPromise<U> thenApplyAsync(Function<? super T, ? extends U> fn, Executor executor, boolean enlistOrigin) { return wrap(delegate.thenApplyAsync(fn, executor), origin(enlistOrigin)); } public DependentPromise<Void> thenAccept(Consumer<? super T> action, boolean enlistOrigin) { return wrap(delegate.thenAccept(action), origin(enlistOrigin)); } public DependentPromise<Void> thenAcceptAsync(Consumer<? super T> action, boolean enlistOrigin) { return wrap(delegate.thenAcceptAsync(action), origin(enlistOrigin)); } public DependentPromise<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor, boolean enlistOrigin) { return wrap(delegate.thenAcceptAsync(action, executor), origin(enlistOrigin)); } public DependentPromise<Void> thenRun(Runnable action, boolean enlistOrigin) { return wrap(delegate.thenRun(action), origin(enlistOrigin)); } public DependentPromise<Void> thenRunAsync(Runnable action, boolean enlistOrigin) { return wrap(delegate.thenRunAsync(action), origin(enlistOrigin)); } public DependentPromise<Void> thenRunAsync(Runnable action, Executor executor, boolean enlistOrigin) { return wrap(delegate.thenRunAsync(action, executor), origin(enlistOrigin)); } public <U, V> DependentPromise<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.thenCombine(other, fn), originAndParam(other, enlistOptions)); } public <U, V> DependentPromise<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.thenCombineAsync(other, fn), originAndParam(other, enlistOptions)); } public <U, V> DependentPromise<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn, Executor executor, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.thenCombineAsync(other, fn, executor), originAndParam(other, enlistOptions)); } public <U> DependentPromise<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.thenAcceptBoth(other, action), originAndParam(other, enlistOptions)); } public <U> DependentPromise<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.thenAcceptBothAsync(other, action), originAndParam(other, enlistOptions)); } public <U> DependentPromise<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action, Executor executor, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.thenAcceptBothAsync(other, action, executor), originAndParam(other, enlistOptions)); } public DependentPromise<Void> runAfterBoth(CompletionStage<?> other, Runnable action, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.runAfterBoth(other, action), originAndParam(other, enlistOptions)); } public DependentPromise<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.runAfterBothAsync(other, action), originAndParam(other, enlistOptions)); } public DependentPromise<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action, Executor executor, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.runAfterBothAsync(other, action, executor), originAndParam(other, enlistOptions)); } public <U> DependentPromise<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.applyToEither(other, fn), originAndParam(other, enlistOptions)); } public <U> DependentPromise<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.applyToEitherAsync(other, fn), originAndParam(other, enlistOptions)); } public <U> DependentPromise<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn, Executor executor, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.applyToEitherAsync(other, fn, executor), originAndParam(other, enlistOptions)); } public DependentPromise<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.acceptEither(other, action), originAndParam(other, enlistOptions)); } public DependentPromise<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.acceptEitherAsync(other, action), originAndParam(other, enlistOptions)); } public DependentPromise<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.acceptEitherAsync(other, action, executor), originAndParam(other, enlistOptions)); } public DependentPromise<Void> runAfterEither(CompletionStage<?> other, Runnable action, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.runAfterEither(other, action), originAndParam(other, enlistOptions)); } public DependentPromise<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.runAfterEitherAsync(other, action), originAndParam(other, enlistOptions)); } public DependentPromise<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action, Executor executor, Set<PromiseOrigin> enlistOptions) { return wrap(delegate.runAfterEitherAsync(other, action, executor), originAndParam(other, enlistOptions)); } public <U> DependentPromise<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn, boolean enlistOrigin) { return wrap(delegate.thenCompose(fn), origin(enlistOrigin)); } public <U> DependentPromise<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, boolean enlistOrigin) { return wrap(delegate.thenComposeAsync(fn), origin(enlistOrigin)); } public <U> DependentPromise<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor, boolean enlistOrigin) { return wrap(delegate.thenComposeAsync(fn, executor), origin(enlistOrigin)); } public DependentPromise<T> exceptionally(Function<Throwable, ? extends T> fn, boolean enlistOrigin) { return wrap(delegate.exceptionally(fn), origin(enlistOrigin)); } @Override public DependentPromise<T> exceptionallyAsync(Function<Throwable, ? extends T> fn, boolean enlistOrigin) { PromiseHolder<T> onError = new PromiseHolder<>(this); return setupExceptionalHandler( handle((r, ex) -> ex == null ? this : onError.modify( handleAsync((r1, ex1) -> fn.apply(ex1), false) ), enlistOrigin), onError); } @Override public DependentPromise<T> exceptionallyAsync(Function<Throwable, ? extends T> fn, Executor executor, boolean enlistOrigin) { PromiseHolder<T> onError = new PromiseHolder<>(this); return setupExceptionalHandler( handle((r, ex) -> ex == null ? this : onError.modify( handleAsync((r1, ex1) -> fn.apply(ex1), executor, false) ), enlistOrigin), onError); } @Override public DependentPromise<T> exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>> fn, boolean enlistOrigin) { return drop( handle((r, ex) -> ex == null ? this : fn.apply(ex), enlistOrigin) ); } @Override public DependentPromise<T> exceptionallyComposeAsync(Function<Throwable, ? extends CompletionStage<T>> fn, boolean enlistOrigin) { PromiseHolder<T> onError = new PromiseHolder<>(this); return setupExceptionalHandler( handle((r, ex) -> ex == null ? this : onError.modify(drop( handleAsync((r1, ex1) -> fn.apply(ex1), false) )), enlistOrigin), onError); } @Override public DependentPromise<T> exceptionallyComposeAsync(Function<Throwable, ? extends CompletionStage<T>> fn, Executor executor, boolean enlistOrigin) { PromiseHolder<T> onError = new PromiseHolder<>(this); return setupExceptionalHandler( handle((r, ex) -> ex == null ? this : onError.modify(drop( handleAsync((r1, ex1) -> fn.apply(ex1), executor, false) )), enlistOrigin), onError); } @Override public DependentPromise<T> thenFilter(Predicate<? super T> predicate, boolean enlistOrigin) { return thenFilter(predicate, NO_SUCH_ELEMENT, enlistOrigin); } @Override public DependentPromise<T> thenFilter(Predicate<? super T> predicate, Function<? super T, Throwable> errorSupplier, boolean enlistOrigin) { return thenCompose(v -> predicate.test(v) ? this : failure(errorSupplier, v), enlistOrigin); } @Override public DependentPromise<T> thenFilterAsync(Predicate<? super T> predicate, boolean enlistOrigin) { return thenFilterAsync(predicate, NO_SUCH_ELEMENT, enlistOrigin); } @Override public DependentPromise<T> thenFilterAsync(Predicate<? super T> predicate, Function<? super T, Throwable> errorSupplier, boolean enlistOrigin) { return thenComposeAsync(v -> predicate.test(v) ? this : failure(errorSupplier, v), enlistOrigin); } @Override public DependentPromise<T> thenFilterAsync(Predicate<? super T> predicate, Executor executor, boolean enlistOrigin) { return thenFilterAsync(predicate, NO_SUCH_ELEMENT, executor, enlistOrigin); } @Override public DependentPromise<T> thenFilterAsync(Predicate<? super T> predicate, Function<? super T, Throwable> errorSupplier, Executor executor, boolean enlistOrigin) { return thenComposeAsync(v -> predicate.test(v) ? this : failure(errorSupplier, v), executor, enlistOrigin); } @Override public DependentPromise<T> whenComplete(BiConsumer<? super T, ? super Throwable> action, boolean enlistOrigin) { return wrap(delegate.whenComplete(action), origin(enlistOrigin)); } @Override public DependentPromise<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, boolean enlistOrigin) { return wrap(delegate.whenCompleteAsync(action), origin(enlistOrigin)); } @Override public DependentPromise<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor, boolean enlistOrigin) { return wrap(delegate.whenCompleteAsync(action, executor), origin(enlistOrigin)); } @Override public <U> DependentPromise<U> handle(BiFunction<? super T, Throwable, ? extends U> fn, boolean enlistOrigin) { return wrap(delegate.handle(fn), origin(enlistOrigin)); } @Override public <U> DependentPromise<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, boolean enlistOrigin) { return wrap(delegate.handleAsync(fn), origin(enlistOrigin)); } @Override public <U> DependentPromise<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor, boolean enlistOrigin) { return wrap(delegate.handleAsync(fn, executor), origin(enlistOrigin)); } @Override public <U> DependentPromise<U> thenApply(Function<? super T, ? extends U> fn) { return thenApply(fn, defaultEnlistOrigin()); } @Override public <U> DependentPromise<U> thenApplyAsync(Function<? super T, ? extends U> fn) { return thenApplyAsync(fn, defaultEnlistOrigin()); } @Override public <U> DependentPromise<U> thenApplyAsync(Function<? super T, ? extends U> fn, Executor executor) { return thenApplyAsync(fn, executor, defaultEnlistOrigin()); } @Override public DependentPromise<Void> thenAccept(Consumer<? super T> action) { return thenAccept(action, defaultEnlistOrigin()); } @Override public DependentPromise<Void> thenAcceptAsync(Consumer<? super T> action) { return thenAcceptAsync(action, defaultEnlistOrigin()); } @Override public DependentPromise<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor) { return thenAcceptAsync(action, executor, defaultEnlistOrigin()); } @Override public DependentPromise<Void> thenRun(Runnable action) { return thenRun(action, defaultEnlistOrigin()); } @Override public DependentPromise<Void> thenRunAsync(Runnable action) { return thenRunAsync(action, defaultEnlistOrigin()); } @Override public DependentPromise<Void> thenRunAsync(Runnable action, Executor executor) { return thenRunAsync(action, executor, defaultEnlistOrigin()); } @Override public <U, V> DependentPromise<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn) { return thenCombine(other, fn, defaultEnlistOptions); } @Override public <U, V> DependentPromise<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn) { return thenCombineAsync(other, fn, defaultEnlistOptions); } @Override public <U, V> DependentPromise<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn, Executor executor) { return thenCombineAsync(other, fn, executor, defaultEnlistOptions); } @Override public <U> DependentPromise<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action) { return thenAcceptBoth(other, action, defaultEnlistOptions); } @Override public <U> DependentPromise<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action) { return thenAcceptBothAsync(other, action, defaultEnlistOptions); } @Override public <U> DependentPromise<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action, Executor executor) { return thenAcceptBothAsync(other, action, executor, defaultEnlistOptions); } @Override public DependentPromise<Void> runAfterBoth(CompletionStage<?> other, Runnable action) { return runAfterBoth(other, action, defaultEnlistOptions); } @Override public DependentPromise<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action) { return runAfterBothAsync(other, action, defaultEnlistOptions); } @Override public DependentPromise<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action, Executor executor) { return runAfterBothAsync(other, action, executor, defaultEnlistOptions); } @Override public <U> DependentPromise<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn) { return applyToEither(other, fn, defaultEnlistOptions); } @Override public <U> DependentPromise<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn) { return applyToEitherAsync(other, fn, defaultEnlistOptions); } @Override public <U> DependentPromise<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn, Executor executor) { return applyToEitherAsync(other, fn, executor, defaultEnlistOptions); } @Override public DependentPromise<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action) { return acceptEither(other, action, defaultEnlistOptions); } @Override public DependentPromise<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action) { return acceptEitherAsync(other, action, defaultEnlistOptions); } @Override public DependentPromise<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor) { return acceptEitherAsync(other, action, executor, defaultEnlistOptions); } @Override public DependentPromise<Void> runAfterEither(CompletionStage<?> other, Runnable action) { return runAfterEither(other, action, defaultEnlistOptions); } @Override public DependentPromise<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action) { return runAfterEitherAsync(other, action, defaultEnlistOptions); } @Override public DependentPromise<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action, Executor executor) { return runAfterEitherAsync(other, action, executor, defaultEnlistOptions); } @Override public <U> DependentPromise<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) { return thenCompose(fn, defaultEnlistOrigin()); } @Override public <U> DependentPromise<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) { return thenComposeAsync(fn, defaultEnlistOrigin()); } @Override public <U> DependentPromise<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor) { return thenComposeAsync(fn, executor, defaultEnlistOrigin()); } @Override public DependentPromise<T> exceptionally(Function<Throwable, ? extends T> fn) { return exceptionally(fn, defaultEnlistOrigin()); } @Override public DependentPromise<T> exceptionallyAsync(Function<Throwable, ? extends T> fn) { return exceptionallyAsync(fn, defaultEnlistOrigin()); } @Override public DependentPromise<T> exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>> fn) { return exceptionallyCompose(fn, defaultEnlistOrigin()); } @Override public DependentPromise<T> exceptionallyComposeAsync(Function<Throwable, ? extends CompletionStage<T>> fn) { return exceptionallyComposeAsync(fn, defaultEnlistOrigin()); } @Override public DependentPromise<T> exceptionallyComposeAsync(Function<Throwable, ? extends CompletionStage<T>> fn, Executor executor) { return exceptionallyComposeAsync(fn, executor, defaultEnlistOrigin()); } @Override public DependentPromise<T> exceptionallyAsync(Function<Throwable, ? extends T> fn, Executor executor) { return exceptionallyAsync(fn, executor, defaultEnlistOrigin()); } @Override public DependentPromise<T> thenFilter(Predicate<? super T> predicate) { return thenFilter(predicate, defaultEnlistOrigin()); } @Override public DependentPromise<T> thenFilter(Predicate<? super T> predicate, Function<? super T, Throwable> errorSupplier) { return thenFilter(predicate, errorSupplier, defaultEnlistOrigin()); } @Override public DependentPromise<T> thenFilterAsync(Predicate<? super T> predicate) { return thenFilterAsync(predicate, defaultEnlistOrigin()); } @Override public DependentPromise<T> thenFilterAsync(Predicate<? super T> predicate, Function<? super T, Throwable> errorSupplier) { return thenFilterAsync(predicate, errorSupplier, defaultEnlistOrigin()); } @Override public DependentPromise<T> thenFilterAsync(Predicate<? super T> predicate, Executor executor) { return thenFilterAsync(predicate, executor, defaultEnlistOrigin()); } @Override public DependentPromise<T> thenFilterAsync(Predicate<? super T> predicate, Function<? super T, Throwable> errorSupplier, Executor executor) { return thenFilterAsync(predicate, errorSupplier, executor, defaultEnlistOrigin()); } @Override public DependentPromise<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) { return whenComplete(action, defaultEnlistOrigin()); } @Override public DependentPromise<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action) { return whenCompleteAsync(action, defaultEnlistOrigin()); } @Override public DependentPromise<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor) { return whenCompleteAsync(action, executor, defaultEnlistOrigin()); } @Override public <U> DependentPromise<U> handle(BiFunction<? super T, Throwable, ? extends U> fn) { return handle(fn, defaultEnlistOrigin()); } @Override public <U> DependentPromise<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn) { return handleAsync(fn, defaultEnlistOrigin()); } @Override public <U> DependentPromise<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) { return handleAsync(fn, executor, defaultEnlistOrigin()); } @Override public DependentPromise<T> dependent() { return dependent(PromiseOrigin.NONE); } public DependentPromise<T> dependent(Set<PromiseOrigin> 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) { if (delegate.cancel(mayInterruptIfRunning)) { cancelPromises(cancellableOrigins, mayInterruptIfRunning); return true; } else { return false; } } @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 Promise<T> unwrap() { if (null == cancellableOrigins || cancellableOrigins.length == 0) { // No state collected, may optimize away own reference return delegate; } else { return cancellablePromiseOf(delegate); } } @Override public Promise<T> 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<T> cancellablePromiseOf(Promise<T> original) { return new UndecoratedCancellationPromise<>(original, cancellableOrigins); } @Override public CompletableFuture<T> toCompletableFuture() { return toCompletableFuture(defaultEnlistOrigin()); } public CompletableFuture<T> toCompletableFuture(boolean enlistOrigin) { if (!enlistOrigin) { return delegate.toCompletableFuture(); } else { CompletablePromise<T> result = new CompletablePromise<T>() { @Override public boolean cancel(boolean mayInterruptIfRunning) { if (ConfigurableDependentPromise.this.cancel(mayInterruptIfRunning)) { return super.cancel(mayInterruptIfRunning); } else { return false; } } }; whenComplete((r, e) -> { if (null != e) { result.onFailure(e); } else { result.onSuccess(r); } }); return result.toCompletableFuture(); } } 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<PromiseOrigin> 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 (null != promises) { Arrays.stream(promises) .filter(p -> p != null) .forEach(p -> cancelPromise(p, mayInterruptIfRunning)); } } static <T> DependentPromise<T> setupExceptionalHandler(DependentPromise<? extends Promise<T>> origin, AtomicReference<? extends Promise<?>> onException) { return (DependentPromise<T>) drop(origin).onCancel(() -> onException.get().cancel(true)) .unwrap(); } static <T> DependentPromise<T> drop(DependentPromise<? extends CompletionStage<T>> lifted) { return lifted.thenCompose(Function.identity(), true); } static <T> CompletionStage<T> failure(Function<? super T, Throwable> errorSupplier, T value) { CompletableFuture<T> result = new CompletableFuture<>(); result.completeExceptionally(errorSupplier.apply(value)); return result; } private static boolean identicalSets(Set<?> a, Set<?> b) { return a.containsAll(b) && b.containsAll(a); } static class UndecoratedCancellationPromise<T> extends AbstractPromiseDecorator<T, Promise<T>> { private final CompletionStage<?>[] dependent; UndecoratedCancellationPromise(Promise<T> 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<T> unwrap() { return unwrap(Promise::unwrap); } @Override public Promise<T> raw() { return unwrap(Promise::raw); } private Promise<T> unwrap(Function<Promise<T>, Promise<T>> fn) { Promise<T> unwrapped = fn.apply(delegate); if (unwrapped == delegate) { return this; } else { return new UndecoratedCancellationPromise<>(unwrapped, dependent); } } @Override protected <U> Promise<U> wrap(CompletionStage<U> original) { // No wrapping by definition return (Promise<U>)original; } } static class PromiseHolder<T> extends AtomicReference<Promise<T>> { private static final long serialVersionUID = 1L; public PromiseHolder(Promise<T> initial) { super(initial); } Promise<T> modify(Promise<T> newValue) { set(newValue); return newValue; } } }