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

nl.talsmasoftware.context.core.concurrent.ContextAwareCompletableFuture Maven / Gradle / Ivy

/*
 * Copyright 2016-2024 Talsma ICT
 *
 * 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 nl.talsmasoftware.context.core.concurrent;

import nl.talsmasoftware.context.ContextManagers;
import nl.talsmasoftware.context.ContextSnapshot;
import nl.talsmasoftware.context.functions.BiConsumerWithContext;
import nl.talsmasoftware.context.functions.BiFunctionWithContext;
import nl.talsmasoftware.context.functions.ConsumerWithContext;
import nl.talsmasoftware.context.functions.FunctionWithContext;
import nl.talsmasoftware.context.functions.RunnableWithContext;
import nl.talsmasoftware.context.functions.SupplierWithContext;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
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 static java.util.Objects.requireNonNull;

/**
 * This class extends the standard {@link CompletableFuture} that was introduced in java version 8.
 * 

* The class is a 'normal' Completable Future, but every successive call made on the result will be made within the * {@link ContextSnapshot context during creation} of this {@link ContextAwareCompletableFuture}. * * @author Sjoerd Talsma */ public class ContextAwareCompletableFuture extends CompletableFuture { /** * Holder for context snapshots to be propagated from one CompletionStage to the next. */ private final ContextSnapshotHolder snapshotHolder; /** * Whether to take a new snapshot after each completion stage. */ private final boolean takeNewSnapshot; /** * Creates a new {@link ContextSnapshot} and remembers that in this completable future, * running all completion methods within this snapshot. * * @see ContextManagers#createContextSnapshot() */ public ContextAwareCompletableFuture() { this((ContextSnapshot) null); } /** * Creates a new {@link CompletableFuture} where all completion methods are run within the specified * snapshot context. * * @param snapshot the snapshot to run completion methods in. * Optional, the completable future will take a new snaphot if {@code null} is provided. * @see ContextManagers#createContextSnapshot() */ public ContextAwareCompletableFuture(ContextSnapshot snapshot) { this(new ContextSnapshotHolder(snapshot), false); } private ContextAwareCompletableFuture(ContextSnapshotHolder holder, boolean takeNewSnapshot) { this.snapshotHolder = requireNonNull(holder, "Snapshot holder is "); this.takeNewSnapshot = takeNewSnapshot; } /** * Runs the {@code supplier} task in the common {@link java.util.concurrent.ForkJoinPool ForkJoinPool} * within the current context and also applies that context to all successive * calls to the {@code CompletableFuture}. * * @param supplier a function to be performed asynchronously returning the result of the CompletableFuture * @param the function's return type * @return The new CompletableFuture that propagates a snapshot of the current context * @see CompletableFuture#supplyAsync(Supplier) * @see ContextAwareCompletableFuture#supplyAsync(Supplier, Executor, ContextSnapshot, boolean) */ public static ContextAwareCompletableFuture supplyAsync(Supplier supplier) { return supplyAsync(supplier, null, null, false); } /** * Runs the {@code supplier} task in the specified {@link Executor executor} * within the current context and also applies that context to all successive * calls to the {@code CompletableFuture}. * * @param supplier a function returning the value to be used to complete the returned CompletableFuture * @param executor the executor to use for asynchronous execution * @param the function's return type * @return The new CompletableFuture that propagates a snapshot of the current context * @see CompletableFuture#supplyAsync(Supplier, Executor) * @see ContextAwareCompletableFuture#supplyAsync(Supplier, Executor, ContextSnapshot, boolean) */ public static ContextAwareCompletableFuture supplyAsync(Supplier supplier, Executor executor) { return supplyAsync(supplier, executor, null, false); } /** * Runs the {@code supplier} task in the specified {@link Executor executor} * within the specified {@link ContextSnapshot context snapshot} and also applies that context * to all successive calls to the {@code CompletableFuture}. *

* This method is lenient to {@code null} values for {@code executor} and {@code snapshot}:
* If {@code executor == null} the common {@link java.util.concurrent.ForkJoinPool ForkJoinPool} is used as * specified by {@link CompletableFuture#supplyAsync(Supplier)}.
* If {@code snapshot == null} a {@link ContextManagers#createContextSnapshot() new context snapshot} is * created for the {@link Supplier} (if not already a {@link SupplierWithContext}). * * @param supplier a function returning the value to be used to complete the returned CompletableFuture * @param executor the executor to use for asynchronous execution * @param snapshot a snapshot of the context to be propagated in the supplier function * and all successive calls of this completable future * @param the function's return type * @return The new CompletableFuture that propagates the specified context snapshot * @see CompletableFuture#supplyAsync(Supplier, Executor) * @see ContextAwareCompletableFuture#supplyAsync(Supplier, Executor, ContextSnapshot, boolean) */ public static ContextAwareCompletableFuture supplyAsync(Supplier supplier, Executor executor, ContextSnapshot snapshot) { return supplyAsync(supplier, executor, snapshot, false); } /** * Runs the {@code supplier} task in the specified {@link Executor executor} * within the specified {@link ContextSnapshot context snapshot} and also applies that context * to all successive calls to the {@code CompletableFuture}. *

* This method is lenient to {@code null} values for {@code executor} and {@code snapshot}:
* If {@code executor == null} the common {@link java.util.concurrent.ForkJoinPool ForkJoinPool} is used as * specified by {@link CompletableFuture#supplyAsync(Supplier)}.
* If {@code snapshot == null} a {@link ContextManagers#createContextSnapshot() new context snapshot} is * created for the {@link Supplier} (if not already a {@link SupplierWithContext}). * * @param supplier a function returning the value to be used to complete the returned CompletableFuture * @param executor the executor to use for asynchronous execution * @param snapshot a snapshot of the context to be propagated in the supplier function * and all successive calls of this completable future * @param takeNewSnapshot whether a new ContextSnapshot should be taken after the supplier function is done. * If {@code false}, the snapshot from the caller propagate to all following completion stages. * If {@code true}, a new snapshot is taken after each completion stage to propagate into the next. * @param the function's return type * @return The new CompletableFuture that propagates the specified context snapshot * @see CompletableFuture#supplyAsync(Supplier, Executor) * @since 1.0.4 */ public static ContextAwareCompletableFuture supplyAsync( Supplier supplier, Executor executor, ContextSnapshot snapshot, boolean takeNewSnapshot) { final ContextSnapshotHolder holder = new ContextSnapshotHolder(snapshot); supplier = new SupplierWithContext(holder, supplier, takeNewSnapshot ? holder : null) { }; return wrap(executor == null ? CompletableFuture.supplyAsync(supplier) : CompletableFuture.supplyAsync(supplier, executor), holder, takeNewSnapshot); } /** * Runs the {@code runnable} task in the common {@link java.util.concurrent.ForkJoinPool ForkJoinPool} * within the current context and also applies that context to all successive * calls to the {@code CompletableFuture}. * * @param runnable the action to run before completing the returned CompletableFuture * @return The new CompletableFuture that propagates a snapshot of the current context * @see CompletableFuture#runAsync(Runnable) * @see ContextAwareCompletableFuture#runAsync(Runnable, Executor, ContextSnapshot, boolean) */ public static ContextAwareCompletableFuture runAsync(Runnable runnable) { return runAsync(runnable, null, null, false); } /** * Runs the {@code runnable} task in the specified {@link Executor executor} * within the current context and also applies that context to all successive * calls to the {@code CompletableFuture}. * * @param runnable the action to run before completing the returned CompletableFuture * @param executor the executor to use for asynchronous execution * @return The new CompletableFuture that propagates a snapshot of the current context * @see CompletableFuture#runAsync(Runnable, Executor) * @see ContextAwareCompletableFuture#runAsync(Runnable, Executor, ContextSnapshot, boolean) */ public static ContextAwareCompletableFuture runAsync(Runnable runnable, Executor executor) { return runAsync(runnable, executor, null, false); } /** * Runs the {@code runnable} task in the specified {@link Executor executor} * within the specified {@link ContextSnapshot context snapshot} and also applies that context * to all successive calls to the {@code CompletableFuture}. *

* This method is lenient to {@code null} values for {@code executor} and {@code snapshot}:
* If {@code executor == null} the common {@link java.util.concurrent.ForkJoinPool ForkJoinPool} is used as * specified by {@link CompletableFuture#supplyAsync(Supplier)}.
* If {@code snapshot == null} a {@link ContextManagers#createContextSnapshot() new context snapshot} is * created for the {@link Supplier} (if not already a {@link SupplierWithContext}). * * @param runnable the action to run before completing the returned CompletableFuture * @param executor the executor to use for asynchronous execution * @param snapshot the context snapshot to apply to the runnable action * @return The new CompletableFuture that propagates a snapshot of the current context * @see CompletableFuture#runAsync(Runnable, Executor) * @see ContextAwareCompletableFuture#runAsync(Runnable, Executor, ContextSnapshot, boolean) */ public static ContextAwareCompletableFuture runAsync(Runnable runnable, Executor executor, ContextSnapshot snapshot) { return runAsync(runnable, executor, snapshot, false); } /** * Runs the {@code runnable} task in the specified {@link Executor executor} * within the specified {@link ContextSnapshot context snapshot} and also applies that context * to all successive calls to the {@code CompletableFuture}. *

* This method is lenient to {@code null} values for {@code executor} and {@code snapshot}:
* If {@code executor == null} the common {@link java.util.concurrent.ForkJoinPool ForkJoinPool} is used as * specified by {@link CompletableFuture#supplyAsync(Supplier)}.
* If {@code snapshot == null} a {@link ContextManagers#createContextSnapshot() new context snapshot} is * created for the {@link Supplier} (if not already a {@link SupplierWithContext}). * * @param runnable the action to run before completing the returned CompletableFuture * @param executor the executor to use for asynchronous execution * @param snapshot the context snapshot to apply to the runnable action * @param takeNewSnapshot whether a new ContextSnapshot should be taken after the supplier function is done. * If {@code false}, the snapshot from the caller propagate to all following completion stages. * If {@code true}, a new snapshot is taken after each completion stage to propagate into the next. * @return The new CompletableFuture that propagates a snapshot of the current context * @see CompletableFuture#runAsync(Runnable, Executor) * @since 1.0.4 */ public static ContextAwareCompletableFuture runAsync( Runnable runnable, Executor executor, ContextSnapshot snapshot, boolean takeNewSnapshot) { final ContextSnapshotHolder holder = new ContextSnapshotHolder(snapshot); runnable = new RunnableWithContext(holder, runnable, takeNewSnapshot ? holder : null) { }; return wrap(executor == null ? CompletableFuture.runAsync(runnable) : CompletableFuture.runAsync(runnable, executor), holder, takeNewSnapshot); } /** * Creates a new {@code ContextAwareCompletableFuture} from the already-completed value. * A new {@linkplain ContextSnapshot} is taken and applied to all * following {@linkplain CompletionStage completion stages}. * * @param value the value to return from the already-completed future. * @param the type of the value * @return New {@code ContextAwareCompletableFuture} returning the completed value * and containing a new {@code ContextSnapshot}. * @see #completedFuture(Object, ContextSnapshot) * @since 1.0.5 */ public static ContextAwareCompletableFuture completedFuture(U value) { return completedFuture(value, null); } /** * Creates a new {@code ContextAwareCompletableFuture} from the already-completed value. * A new {@linkplain ContextSnapshot} is taken and applied to all * following {@linkplain CompletionStage completion stages}. * * @param value the value to return from the already-completed future. * @param snapshot the context snapshot to apply to following completion stages * (optional, specify {@code null} to take a new snapshot) * @param the type of the value * @return New {@code ContextAwareCompletableFuture} returning the completed value * and containing the specified {@code ContextSnapshot}. * @since 1.0.5 */ public static ContextAwareCompletableFuture completedFuture(U value, ContextSnapshot snapshot) { final ContextAwareCompletableFuture completedFuture = new ContextAwareCompletableFuture<>(snapshot); completedFuture.complete(value); return completedFuture; } /** * Creates a new {@code CompletionStage} from the already-completed value. * A new {@linkplain ContextSnapshot} is taken and applied to all * following {@linkplain CompletionStage completion stages}. * * @param value the value to return from the already-completed stage. * @param the type of the value * @return New {@code CompletionStage} returning the completed value * and containing a new {@code ContextSnapshot}. * @see #completedFuture(Object, ContextSnapshot) * @since 1.0.5 */ public static CompletionStage completedStage(U value) { return completedFuture(value, null); } /** * Creates a new {@code ContextAwareCompletableFuture} that is already completed * exceptionally with the given exception. * A new {@linkplain ContextSnapshot} is taken and applied to all * following {@linkplain CompletionStage completion stages}. * * @param ex the exception * @param the type of the value * @return New {@code ContextAwareCompletableFuture} throwing the exception * and containing a new {@code ContextSnapshot}. * @see #failedFuture(Throwable, ContextSnapshot) * @since 1.0.5 */ public static ContextAwareCompletableFuture failedFuture(Throwable ex) { return failedFuture(ex, null); } /** * Creates a new {@code ContextAwareCompletableFuture} that is already completed * exceptionally with the given exception. * The specified {@code snapshot} is applied to all * following {@linkplain CompletionStage completion stages}. * * @param ex the exception * @param snapshot the context snapshot to apply to following completion stages * (optional, specify {@code null} to take a new snapshot) * @param the type of the value * @return New {@code ContextAwareCompletableFuture} throwing the exception * and containing the specified {@code snapshot}. * @since 1.0.5 */ public static ContextAwareCompletableFuture failedFuture(Throwable ex, ContextSnapshot snapshot) { final ContextAwareCompletableFuture failedFuture = new ContextAwareCompletableFuture<>(snapshot); failedFuture.completeExceptionally(ex); return failedFuture; } /** * Creates a new {@code CompletionStage} that is already completed * exceptionally with the given exception. * A new {@linkplain ContextSnapshot} is taken and applied to all * following {@linkplain CompletionStage completion stages}. * * @param ex the exception * @param the type of the value * @return New {@code CompletionStage} throwing the exception * and containing a new {@code ContextSnapshot}. * @see #failedFuture(Throwable, ContextSnapshot) * @since 1.0.5 */ public static CompletionStage failedStage(Throwable ex) { return failedFuture(ex, null); } /** * Returns a new CompletableFuture that is completed when all of * the given CompletableFutures complete. If any of the given * CompletableFutures complete exceptionally, then the returned * CompletableFuture also does so, with a CompletionException * holding this exception as its cause. Otherwise, the results, * if any, of the given CompletableFutures are not reflected in * the returned CompletableFuture, but may be obtained by * inspecting them individually. If no CompletableFutures are * provided, returns a CompletableFuture completed with the value * {@code null}. *

* Among the applications of this method is to await completion * of a set of independent CompletableFutures before continuing a * program, as in: {@code CompletableFuture.allOf(c1, c2, * c3).join();}. *

* A new {@linkplain ContextSnapshot} is taken and applied to all * following {@linkplain CompletionStage completion stages}. * * @param cfs the CompletableFutures * @return A new {@code ContextAwareCompletableFuture} that is completed when all of the * given CompletableFutures complete * @throws NullPointerException if the array or any of its elements are {@code null} * @since 1.0.5 */ public static ContextAwareCompletableFuture allOf(CompletableFuture... cfs) { return allOf((ContextSnapshot) null, cfs); } /** * Returns a new CompletableFuture that is completed when all of * the given CompletableFutures complete. If any of the given * CompletableFutures complete exceptionally, then the returned * CompletableFuture also does so, with a CompletionException * holding this exception as its cause. Otherwise, the results, * if any, of the given CompletableFutures are not reflected in * the returned CompletableFuture, but may be obtained by * inspecting them individually. If no CompletableFutures are * provided, returns a CompletableFuture completed with the value * {@code null}. *

* Among the applications of this method is to await completion * of a set of independent CompletableFutures before continuing a * program, as in: {@code CompletableFuture.allOf(c1, c2, * c3).join();}. *

* The specified {@linkplain ContextSnapshot} is applied to all * following {@linkplain CompletionStage completion stages}. * * @param snapshot the context snapshot to apply to following completion stages * (optional, specify {@code null} to take a new snapshot) * @param cfs the CompletableFutures * @return A new {@code ContextAwareCompletableFuture} that is completed when all of the * given CompletableFutures complete * @throws NullPointerException if the array or any of its elements are {@code null} * @since 1.0.5 */ public static ContextAwareCompletableFuture allOf(ContextSnapshot snapshot, CompletableFuture... cfs) { final ContextSnapshotHolder holder = new ContextSnapshotHolder(snapshot); return wrap(CompletableFuture.allOf(cfs), holder, false); } /** * Returns a new CompletableFuture that is completed when any of * the given CompletableFutures complete, with the same result. * Otherwise, if it completed exceptionally, the returned * CompletableFuture also does so, with a CompletionException * holding this exception as its cause. If no CompletableFutures * are provided, returns an incomplete CompletableFuture. *

* A new {@linkplain ContextSnapshot} is taken and applied to all * following {@linkplain CompletionStage completion stages}. * * @param cfs the CompletableFutures * @return a new CompletableFuture that is completed with the result or exception * of any of the given CompletableFutures when one completes * @throws NullPointerException if the array or any of its elements are {@code null} * @since 1.0.5 */ public static ContextAwareCompletableFuture anyOf(CompletableFuture... cfs) { return anyOf((ContextSnapshot) null, cfs); } /** * Returns a new CompletableFuture that is completed when any of * the given CompletableFutures complete, with the same result. * Otherwise, if it completed exceptionally, the returned * CompletableFuture also does so, with a CompletionException * holding this exception as its cause. If no CompletableFutures * are provided, returns an incomplete CompletableFuture. *

* The specified {@linkplain ContextSnapshot} is applied to all * following {@linkplain CompletionStage completion stages}. * * @param snapshot the context snapshot to apply to following completion stages * (optional, specify {@code null} to take a new snapshot) * @param cfs the CompletableFutures * @return a new CompletableFuture that is completed with the result or exception * of any of the given CompletableFutures when one completes * @throws NullPointerException if the array or any of its elements are {@code null} * @since 1.0.5 */ public static ContextAwareCompletableFuture anyOf(ContextSnapshot snapshot, CompletableFuture... cfs) { final ContextSnapshotHolder holder = new ContextSnapshotHolder(snapshot); return wrap(CompletableFuture.anyOf(cfs), holder, false); } private static ContextAwareCompletableFuture wrap(CompletableFuture completableFuture, ContextSnapshotHolder holder, boolean takeNewSnapshot) { ContextAwareCompletableFuture contextAwareCompletableFuture = new ContextAwareCompletableFuture<>(holder, takeNewSnapshot); completableFuture.whenComplete((result, throwable) -> { if (throwable != null) contextAwareCompletableFuture.completeExceptionally(throwable); else contextAwareCompletableFuture.complete(result); }); return contextAwareCompletableFuture; } /** * @return The {@code snapshotHolder} if {@code takeNewSnapshot == true} or otherwise {@code null}. */ private Consumer resultSnapshotConsumer() { return takeNewSnapshot ? snapshotHolder : null; } /** * Returns a context-aware CompletableFuture that takes a new snapshot after each completion stage. *

* This means that after each {@code then...}, {@code run...}, {@code apply...} method, * after calling the function, a new context snapshot is taken for follow-up calls. *

* Only use this when chaining completable futures where the completion stages may update contextual values.
* Warning: This may result in unnecessary context snapshots being taken. * * @return A new context-aware completable future where context changes also propagate accross completion stages. * @see CompletionStage */ public ContextAwareCompletableFuture takeNewSnapshot() { return takeNewSnapshot(true); } /** * Returns a context-aware CompletableFuture that may take a new snapshot after each completion stage. *

* This means that after each {@code then...}, {@code run...}, {@code apply...} method, * after calling the function, a new context snapshot is taken for follow-up calls. *

* Only set this to {@code true} when chaining completable futures where the completion stages * may update contextual values.
* Warning: This may result in unnecessary context snapshots being taken. * * @param takeSnapshot whether new context snapshots must be taken after each completion stage. * @return A context-aware completable future where context changes also propagate accross completion stages * if {@code takeSnapshot} is {@code true}. * @see CompletionStage */ public ContextAwareCompletableFuture takeNewSnapshot(boolean takeSnapshot) { return this.takeNewSnapshot == takeSnapshot ? this : wrap(this, snapshotHolder, takeSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenApply(Function fn) { return wrap(super.thenApply(new FunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenApplyAsync(Function fn) { return wrap(super.thenApplyAsync(new FunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenApplyAsync(Function fn, Executor executor) { return wrap(super.thenApplyAsync(new FunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }, executor), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenAccept(Consumer action) { return wrap(super.thenAccept(new ConsumerWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenAcceptAsync(Consumer action) { return wrap(super.thenAcceptAsync(new ConsumerWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenAcceptAsync(Consumer action, Executor executor) { return wrap(super.thenAcceptAsync(new ConsumerWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }, executor), snapshotHolder, takeNewSnapshot); } @Override public ContextAwareCompletableFuture thenRun(Runnable action) { return wrap(super.thenRun(new RunnableWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override public CompletableFuture thenRunAsync(Runnable action) { return wrap(super.thenRunAsync(new RunnableWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override public ContextAwareCompletableFuture thenRunAsync(Runnable action, Executor executor) { return wrap(super.thenRunAsync(new RunnableWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }, executor), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenCombine( CompletionStage other, BiFunction fn) { return wrap(super.thenCombine(other, new BiFunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenCombineAsync( CompletionStage other, BiFunction fn) { return wrap(super.thenCombineAsync(other, new BiFunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenCombineAsync( CompletionStage other, BiFunction fn, Executor executor) { return wrap(super.thenCombineAsync(other, new BiFunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }, executor), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenAcceptBoth( CompletionStage other, BiConsumer action) { return wrap(super.thenAcceptBoth(other, new BiConsumerWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenAcceptBothAsync( CompletionStage other, BiConsumer action) { return wrap(super.thenAcceptBothAsync(other, new BiConsumerWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenAcceptBothAsync( CompletionStage other, BiConsumer action, Executor executor) { return wrap(super.thenAcceptBothAsync(other, new BiConsumerWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }, executor), snapshotHolder, takeNewSnapshot); } @Override public ContextAwareCompletableFuture runAfterBoth(CompletionStage other, Runnable action) { return wrap(super.runAfterBoth(other, new RunnableWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override public ContextAwareCompletableFuture runAfterBothAsync(CompletionStage other, Runnable action) { return wrap(super.runAfterBothAsync(other, new RunnableWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override public ContextAwareCompletableFuture runAfterBothAsync(CompletionStage other, Runnable action, Executor executor) { return wrap(super.runAfterBothAsync(other, new RunnableWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }, executor), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture applyToEither(CompletionStage other, Function fn) { // Don't gamble which completion stage might win, create a new holder for the resulting function instead. final ContextSnapshotHolder newHolder = new ContextSnapshotHolder(snapshotHolder.get()); return wrap(super.applyToEither(other, new FunctionWithContext(newHolder, fn, takeNewSnapshot ? newHolder : null) { }), newHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture applyToEitherAsync(CompletionStage other, Function fn) { // Don't gamble which completion stage might win, create a new holder for the resulting function instead. final ContextSnapshotHolder newHolder = new ContextSnapshotHolder(snapshotHolder.get()); return wrap(super.applyToEitherAsync(other, new FunctionWithContext(newHolder, fn, takeNewSnapshot ? newHolder : null) { }), newHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture applyToEitherAsync( CompletionStage other, Function fn, Executor executor) { // Don't gamble which completion stage might win, create a new holder for the resulting function instead. final ContextSnapshotHolder newHolder = new ContextSnapshotHolder(snapshotHolder.get()); return wrap(super.applyToEitherAsync(other, new FunctionWithContext(newHolder, fn, takeNewSnapshot ? newHolder : null) { }, executor), newHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture acceptEither(CompletionStage other, Consumer action) { // Don't gamble which completion stage might win, create a new holder for the resulting function instead. final ContextSnapshotHolder newHolder = new ContextSnapshotHolder(snapshotHolder.get()); return wrap(super.acceptEither(other, new ConsumerWithContext(newHolder, action, takeNewSnapshot ? newHolder : null) { }), newHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture acceptEitherAsync(CompletionStage other, Consumer action) { // Don't gamble which completion stage might win, create a new holder for the resulting function instead. final ContextSnapshotHolder newHolder = new ContextSnapshotHolder(snapshotHolder.get()); return wrap(super.acceptEitherAsync(other, new ConsumerWithContext(newHolder, action, takeNewSnapshot ? newHolder : null) { }), newHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture acceptEitherAsync( CompletionStage other, Consumer action, Executor executor) { // Don't gamble which completion stage might win, create a new holder for the resulting function instead. final ContextSnapshotHolder newHolder = new ContextSnapshotHolder(snapshotHolder.get()); return wrap(super.acceptEitherAsync(other, new ConsumerWithContext(newHolder, action, takeNewSnapshot ? newHolder : null) { }, executor), newHolder, takeNewSnapshot); } @Override public ContextAwareCompletableFuture runAfterEither(CompletionStage other, Runnable action) { // Don't gamble which completion stage might win, create a new holder for the resulting function instead. final ContextSnapshotHolder newHolder = new ContextSnapshotHolder(snapshotHolder.get()); return wrap(super.runAfterEither(other, new RunnableWithContext(newHolder, action, takeNewSnapshot ? newHolder : null) { }), newHolder, takeNewSnapshot); } @Override public ContextAwareCompletableFuture runAfterEitherAsync(CompletionStage other, Runnable action) { // Don't gamble which completion stage might win, create a new holder for the resulting function instead. final ContextSnapshotHolder newHolder = new ContextSnapshotHolder(snapshotHolder.get()); return wrap(super.runAfterEitherAsync(other, new RunnableWithContext(newHolder, action, takeNewSnapshot ? newHolder : null) { }), newHolder, takeNewSnapshot); } @Override public ContextAwareCompletableFuture runAfterEitherAsync(CompletionStage other, Runnable action, Executor executor) { // Don't gamble which completion stage might win, create a new holder for the resulting function instead. final ContextSnapshotHolder newHolder = new ContextSnapshotHolder(snapshotHolder.get()); return wrap(super.runAfterEitherAsync(other, new RunnableWithContext(newHolder, action, takeNewSnapshot ? newHolder : null) { }, executor), newHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenCompose(Function> fn) { return wrap(super.thenCompose(new FunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenComposeAsync(Function> fn) { return wrap(super.thenComposeAsync(new FunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture thenComposeAsync(Function> fn, Executor executor) { return wrap(super.thenComposeAsync(new FunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }, executor), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture whenComplete(BiConsumer action) { return wrap(super.whenComplete(new BiConsumerWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture whenCompleteAsync(BiConsumer action) { return wrap(super.whenCompleteAsync(new BiConsumerWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture whenCompleteAsync(BiConsumer action, Executor executor) { return wrap(super.whenCompleteAsync(new BiConsumerWithContext(snapshotHolder, action, resultSnapshotConsumer()) { }, executor), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture handle(BiFunction fn) { return wrap(super.handle(new BiFunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture handleAsync(BiFunction fn) { return wrap(super.handleAsync(new BiFunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture handleAsync(BiFunction fn, Executor executor) { return wrap(super.handleAsync(new BiFunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }, executor), snapshotHolder, takeNewSnapshot); } @Override @SuppressWarnings("unchecked") public ContextAwareCompletableFuture exceptionally(Function fn) { return wrap(super.exceptionally(new FunctionWithContext(snapshotHolder, fn, resultSnapshotConsumer()) { }), snapshotHolder, takeNewSnapshot); } }