diff --git a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java index 45d3e0fd..3d61cc94 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java @@ -1710,6 +1710,37 @@ C completeAsync(C cf, Supplier supplier, Executor executor) { return cf; } + /** + * If not already completed, completes given CompletableFuture with the exception result + * of the given Supplier function invoked from an asynchronous task using the default executor. + * + * @param supplier a function returning the value to be used to complete given CompletableFuture + * @return the given CompletableFuture + * @see CompletableFuture#completeExceptionally(Throwable) + */ + public static > + C completeExceptionallyAsync(C cf, Supplier supplier) { + return completeExceptionallyAsync(cf, supplier, AsyncPoolHolder.ASYNC_POOL); + } + + /** + * If not already completed, completes given CompletableFuture with the exception result + * of the given Supplier function invoked from an asynchronous task using the given executor. + * + * @param supplier a function returning the value to be used to complete given CompletableFuture + * @param executor the executor to use for asynchronous execution + * @return the given CompletableFuture + * @see CompletableFuture#completeExceptionally(Throwable) + */ + public static > + C completeExceptionallyAsync(C cf, Supplier supplier, Executor executor) { + requireNonNull(supplier, "supplier is null"); + requireNonNull(executor, "executor is null"); + // below code is copied from CompletableFuture#completeAsync with small adoption + executor.execute(new CfExCompleterBySupplier(cf, supplier)); + return cf; + } + //# Re-Config methods /** diff --git a/cffu-core/src/main/java/io/foldright/cffu/DelayExecutionHelpers.java b/cffu-core/src/main/java/io/foldright/cffu/DelayExecutionHelpers.java index 17d3c207..b2c53ce7 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/DelayExecutionHelpers.java +++ b/cffu-core/src/main/java/io/foldright/cffu/DelayExecutionHelpers.java @@ -17,7 +17,10 @@ /** * Singleton delay scheduler, used only for starting and cancelling tasks + *

+ * code is copied from {@link CompletableFuture.Delayer} with small adoption. */ +@SuppressWarnings("JavadocReference") final class Delayer { private static final ScheduledThreadPoolExecutor delayer; @@ -82,7 +85,10 @@ private Delayer() { /** * An executor wrapper with delayed execution. + *

+ * code is copied from {@link CompletableFuture.DelayedExecutor} with small adoption. */ +@SuppressWarnings("JavadocReference") final class DelayedExecutor implements Executor { private final long delay; private final TimeUnit unit; @@ -106,8 +112,11 @@ public void execute(@NonNull Runnable r) { //////////////////////////////////////////////////////////////////////////////// /** - * Action to submit task(Runnable) to executor + * Action to submit task(Runnable) to executor. + *

+ * code is copied from {@link CompletableFuture.TaskSubmitter} with small adoption. */ +@SuppressWarnings("JavadocReference") final class TaskSubmitter implements Runnable { private final Executor executor; private final Runnable action; @@ -124,8 +133,11 @@ public void run() { } /** - * Action to cf.completeExceptionally with TimeoutException + * Action to cf.completeExceptionally with TimeoutException. + *

+ * code is copied from {@link CompletableFuture.Timeout} with small adoption. */ +@SuppressWarnings("JavadocReference") final class CfTimeout implements Runnable { private final CompletableFuture cf; @@ -141,8 +153,11 @@ public void run() { } /** - * Action to complete cf + * Action to complete cf. + *

+ * code is copied from {@link CompletableFuture.DelayedCompleter} with small adoption. */ +@SuppressWarnings("JavadocReference") final class CfCompleter implements Runnable { private final CompletableFuture cf; private final T value; @@ -159,12 +174,15 @@ public void run() { } /** - * Action to cancel unneeded scheduled task by Future (for example timeouts) + * Action to cancel unneeded scheduled task by Future (for example timeouts). + *

+ * code is copied from {@link CompletableFuture.Canceller} with small adoption. * * @see Delayer#delay(Runnable, long, TimeUnit) * @see Delayer#delayToTimoutCf(CompletableFuture, long, TimeUnit) * @see Delayer#delayToCompleteCf(CompletableFuture, Object, long, TimeUnit) */ +@SuppressWarnings("JavadocReference") final class FutureCanceller implements BiConsumer { private final Future f; @@ -180,9 +198,8 @@ public void accept(Object ignore, Throwable ex) { } /** - * code is copied from {@code CompletableFuture#AsyncSupply} with small adoption. + * code is copied from {@code CompletableFuture.AsyncSupply} with small adoption. */ -@SuppressWarnings("serial") @SuppressFBWarnings("SE_BAD_FIELD") final class CfCompleterBySupplier extends ForkJoinTask implements Runnable, CompletableFuture.AsynchronousCompletionTask { @@ -226,3 +243,50 @@ public void run() { } } } + +/** + * code is adopted from {@code CompletableFuture.AsyncSupply}. + */ +@SuppressFBWarnings("SE_BAD_FIELD") +final class CfExCompleterBySupplier extends ForkJoinTask + implements Runnable, CompletableFuture.AsynchronousCompletionTask { + private CompletableFuture dep; + private Supplier fn; + + CfExCompleterBySupplier(CompletableFuture dep, Supplier fn) { + this.dep = dep; + this.fn = fn; + } + + @Override + public Void getRawResult() { + return null; + } + + @Override + public void setRawResult(Void v) { + } + + @Override + public boolean exec() { + run(); + return false; + } + + @Override + public void run() { + CompletableFuture d; + Supplier f; + if ((d = dep) != null && (f = fn) != null) { + dep = null; + fn = null; + if (!d.isDone()) { + try { + d.completeExceptionally(f.get()); + } catch (Throwable ex) { + d.completeExceptionally(ex); + } + } + } + } +}