net.tascalate.concurrent.ConfigurableDependentPromise Maven / Gradle / Ivy
Show all versions of net.tascalate.concurrent Show documentation
/**
* Copyright 2015-2019 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.LinkedCompletion.FutureCompletion;
import static net.tascalate.concurrent.SharedFunctions.cancelPromise;
import static net.tascalate.concurrent.SharedFunctions.selectFirst;
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.Supplier;
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 {
final protected Promise delegate;
final protected CompletionStage>[] cancellableOrigins;
final private 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;
}
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 (null == cancellableOrigins || cancellableOrigins.length == 0) {
// 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;
}
}
}
final ConfigurableDependentPromise 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;
}
// 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) {
if (!(delayOnError || enlistOrigin)) {
// Fast route
return thenCompose(
v -> thenCombineAsync(Timeouts.delay(duration), selectFirst(), PromiseOrigin.PARAM_ONLY)
);
}
CompletableFuture> 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 orTimeout(Duration duration, boolean cancelOnTimeout) {
return orTimeout(duration, cancelOnTimeout, defaultEnlistOrigin());
}
@Override
public DependentPromise orTimeout(Duration duration, boolean cancelOnTimeout, boolean enlistOrigin) {
Promise extends Try> onTimeout = Timeouts.delayed(null, duration);
DependentPromise 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 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) {
Promise> onTimeout = Timeouts.delayed(Try.success(value), duration);
DependentPromise 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 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) {
// timeout converted to supplier
Promise>> onTimeout = Timeouts.delayed(Try.with(supplier), duration);
DependentPromise 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 DependentPromise thenApply(Function super T, ? extends U> fn, boolean enlistOrigin) {
return wrap(delegate.thenApply(fn), origin(enlistOrigin));
}
public DependentPromise thenApplyAsync(Function super T, ? extends U> fn, boolean enlistOrigin) {
return wrap(delegate.thenApplyAsync(fn), origin(enlistOrigin));
}
public DependentPromise thenApplyAsync(Function super T, ? extends U> fn, Executor executor, boolean enlistOrigin) {
return wrap(delegate.thenApplyAsync(fn, executor), origin(enlistOrigin));
}
public DependentPromise thenAccept(Consumer super T> action, boolean enlistOrigin) {
return wrap(delegate.thenAccept(action), origin(enlistOrigin));
}
public DependentPromise thenAcceptAsync(Consumer super T> action, boolean enlistOrigin) {
return wrap(delegate.thenAcceptAsync(action), origin(enlistOrigin));
}
public DependentPromise thenAcceptAsync(Consumer super T> action, Executor executor, boolean enlistOrigin) {
return wrap(delegate.thenAcceptAsync(action, executor), origin(enlistOrigin));
}
public DependentPromise thenRun(Runnable action, boolean enlistOrigin) {
return wrap(delegate.thenRun(action), origin(enlistOrigin));
}
public DependentPromise thenRunAsync(Runnable action, boolean enlistOrigin) {
return wrap(delegate.thenRunAsync(action), origin(enlistOrigin));
}
public DependentPromise thenRunAsync(Runnable action, Executor executor, boolean enlistOrigin) {
return wrap(delegate.thenRunAsync(action, executor), origin(enlistOrigin));
}
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));
}
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));
}
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));
}
public DependentPromise thenAcceptBoth(CompletionStage extends U> other,
BiConsumer super T, ? super U> action,
Set enlistOptions) {
return wrap(delegate.thenAcceptBoth(other, action), originAndParam(other, enlistOptions));
}
public DependentPromise thenAcceptBothAsync(CompletionStage extends U> other,
BiConsumer super T, ? super U> action,
Set enlistOptions) {
return wrap(delegate.thenAcceptBothAsync(other, action), originAndParam(other, enlistOptions));
}
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));
}
public DependentPromise runAfterBoth(CompletionStage> other, Runnable action, Set enlistOptions) {
return wrap(delegate.runAfterBoth(other, action), originAndParam(other, enlistOptions));
}
public DependentPromise runAfterBothAsync(CompletionStage> other, Runnable action, Set enlistOptions) {
return wrap(delegate.runAfterBothAsync(other, action), originAndParam(other, enlistOptions));
}
public DependentPromise runAfterBothAsync(CompletionStage> other,
Runnable action,
Executor executor,
Set enlistOptions) {
return wrap(delegate.runAfterBothAsync(other, action, executor), originAndParam(other, enlistOptions));
}
public DependentPromise applyToEither(CompletionStage extends T> other,
Function super T, U> fn,
Set enlistOptions) {
return wrap(delegate.applyToEither(other, fn), originAndParam(other, enlistOptions));
}
public DependentPromise applyToEitherAsync(CompletionStage extends T> other,
Function super T, U> fn,
Set enlistOptions) {
return wrap(delegate.applyToEitherAsync(other, fn), originAndParam(other, enlistOptions));
}
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));
}
public DependentPromise acceptEither(CompletionStage extends T> other,
Consumer super T> action,
Set enlistOptions) {
return wrap(delegate.acceptEither(other, action), originAndParam(other, enlistOptions));
}
public DependentPromise acceptEitherAsync(CompletionStage extends T> other,
Consumer super T> action,
Set enlistOptions) {
return wrap(delegate.acceptEitherAsync(other, action), originAndParam(other, enlistOptions));
}
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));
}
public DependentPromise runAfterEither(CompletionStage> other, Runnable action, Set enlistOptions) {
return wrap(delegate.runAfterEither(other, action), originAndParam(other, enlistOptions));
}
public DependentPromise runAfterEitherAsync(CompletionStage> other, Runnable action, Set enlistOptions) {
return wrap(delegate.runAfterEitherAsync(other, action), originAndParam(other, enlistOptions));
}
public DependentPromise runAfterEitherAsync(CompletionStage> other,
Runnable action,
Executor executor,
Set enlistOptions) {
return wrap(delegate.runAfterEitherAsync(other, action, executor), originAndParam(other, enlistOptions));
}
public DependentPromise thenCompose(Function super T, ? extends CompletionStage> fn, boolean enlistOrigin) {
return wrap(delegate.thenCompose(fn), origin(enlistOrigin));
}
public DependentPromise thenComposeAsync(Function super T, ? extends CompletionStage> fn, boolean enlistOrigin) {
return wrap(delegate.thenComposeAsync(fn), origin(enlistOrigin));
}
public DependentPromise thenComposeAsync(Function super T, ? extends CompletionStage> fn, Executor executor, boolean enlistOrigin) {
return wrap(delegate.thenComposeAsync(fn, executor), origin(enlistOrigin));
}
public DependentPromise exceptionally(Function fn, boolean enlistOrigin) {
return wrap(delegate.exceptionally(fn), origin(enlistOrigin));
}
public DependentPromise whenComplete(BiConsumer super T, ? super Throwable> action, boolean enlistOrigin) {
return wrap(delegate.whenComplete(action), origin(enlistOrigin));
}
public DependentPromise whenCompleteAsync(BiConsumer super T, ? super Throwable> action, boolean enlistOrigin) {
return wrap(delegate.whenCompleteAsync(action), origin(enlistOrigin));
}
public DependentPromise whenCompleteAsync(BiConsumer super T, ? super Throwable> action, Executor executor, boolean enlistOrigin) {
return wrap(delegate.whenCompleteAsync(action, executor), origin(enlistOrigin));
}
public DependentPromise handle(BiFunction super T, Throwable, ? extends U> fn, boolean enlistOrigin) {
return wrap(delegate.handle(fn), origin(enlistOrigin));
}
public DependentPromise handleAsync(BiFunction super T, Throwable, ? extends U> fn, boolean enlistOrigin) {
return wrap(delegate.handleAsync(fn), origin(enlistOrigin));
}
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 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);
}
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) {
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 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());
}
public CompletableFuture toCompletableFuture(boolean enlistOrigin) {
if (!enlistOrigin) {
return delegate.toCompletableFuture();
} else {
FutureCompletion result = new FutureCompletion().dependsOn(this);
whenComplete((r, e) -> {
if (null != e) {
result.completeExceptionally(e);
} else {
result.complete(r);
}
});
return result;
}
}
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 (null != 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);
}
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 raw() {
// May not unwrap further
return this;
}
@Override
protected Promise wrap(CompletionStage original) {
// No wrapping by definition
return (Promise)original;
}
}
}