org.spf4j.concurrent.ContextPropagatingCompletableFuture Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spf4j-core Show documentation
Show all versions of spf4j-core Show documentation
A continuously growing collection of utilities to measure performance, get better diagnostics,
improve performance, or do things more reliably, faster that other open source libraries...
package org.spf4j.concurrent;
import com.google.common.annotations.Beta;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.CompletableFuture;
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 javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.spf4j.base.ExecutionContext;
import org.spf4j.base.ExecutionContexts;
import org.spf4j.base.TimeSource;
import org.spf4j.base.Timing;
import org.spf4j.base.UncheckedTimeoutException;
/**
* A Completable future that will wrap all Functions to properly propagate ExecutionContext.
* see CompletableFuture javadoc for more detail.
*
* This works properly only in JDK 11.
*
* @author Zoltan Farkas
*/
@SuppressWarnings("checkstyle:DesignForExtension")
@Beta
@ParametersAreNonnullByDefault
public class ContextPropagatingCompletableFuture
extends InterruptibleCompletableFuture {
private final ExecutionContext parentContext;
private final long deadlinenanos;
@SuppressFBWarnings("EI_EXPOSE_REP2")
public ContextPropagatingCompletableFuture(final ExecutionContext parentContext, final long deadlinenanos) {
this.parentContext = parentContext;
this.deadlinenanos = deadlinenanos;
}
@Override
public CompletableFuture thenApply(final Function super T, ? extends U> fn) {
return super.thenApply(ExecutionContexts.propagatingFunction(fn, parentContext,
null, deadlinenanos));
}
@Override
public CompletableFuture thenApplyAsync(final Function super T, ? extends U> fn) {
return super.thenApplyAsync(ExecutionContexts.propagatingFunction(fn, parentContext,
null, deadlinenanos));
}
@Override
public CompletableFuture thenApplyAsync(final Function super T, ? extends U> fn, final Executor executor) {
return super.thenApplyAsync(ExecutionContexts.propagatingFunction(fn, parentContext,
null, deadlinenanos), executor);
}
@Override
public CompletableFuture thenAccept(final Consumer super T> action) {
return super.thenAccept(ExecutionContexts.propagatingConsumer(action,
parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture thenAcceptAsync(final Consumer super T> action) {
return super.thenAcceptAsync(ExecutionContexts.propagatingConsumer(action,
parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture thenAcceptAsync(final Consumer super T> action, final Executor executor) {
return super.thenAcceptAsync(ExecutionContexts.propagatingConsumer(action,
parentContext, null, deadlinenanos), executor);
}
@Override
public CompletableFuture thenRun(final Runnable action) {
return super.thenRun(ExecutionContexts.propagatingRunnable(action, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture thenRunAsync(final Runnable action) {
return super.thenRunAsync(
ExecutionContexts.propagatingRunnable(action, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture thenRunAsync(final Runnable action, final Executor executor) {
return super.thenRunAsync(
ExecutionContexts.propagatingRunnable(action, parentContext, null, deadlinenanos), executor);
}
@Override
public CompletableFuture thenCombine(final CompletionStage extends U> other,
final BiFunction super T, ? super U, ? extends V> fn) {
return super.thenCombine(other,
ExecutionContexts.propagatingBiFunction(fn, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture thenCombineAsync(final CompletionStage extends U> other,
final BiFunction super T, ? super U, ? extends V> fn) {
return super.thenCombineAsync(other,
ExecutionContexts.propagatingBiFunction(fn, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture thenCombineAsync(final CompletionStage extends U> other,
final BiFunction super T, ? super U, ? extends V> fn, final Executor executor) {
return super.thenCombineAsync(other,
ExecutionContexts.propagatingBiFunction(fn, parentContext, null, deadlinenanos),
executor);
}
@Override
public CompletableFuture thenAcceptBoth(final CompletionStage extends U> other,
final BiConsumer super T, ? super U> action) {
return super.thenAcceptBoth(other, ExecutionContexts.propagatingBiConsumer(action, parentContext,
null, deadlinenanos));
}
@Override
public CompletableFuture thenAcceptBothAsync(final CompletionStage extends U> other,
final BiConsumer super T, ? super U> action) {
return super.thenAcceptBothAsync(other,
ExecutionContexts.propagatingBiConsumer(action, parentContext,
null, deadlinenanos));
}
@Override
public CompletableFuture thenAcceptBothAsync(final CompletionStage extends U> other,
final BiConsumer super T, ? super U> action, final Executor executor) {
return super.thenAcceptBothAsync(other,
ExecutionContexts.propagatingBiConsumer(action, parentContext,
null, deadlinenanos), executor);
}
@Override
public CompletableFuture runAfterBoth(final CompletionStage> other, final Runnable action) {
return super.runAfterBoth(other,
ExecutionContexts.propagatingRunnable(action, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture runAfterBothAsync(final CompletionStage> other, final Runnable action) {
return super.runAfterBothAsync(other, ExecutionContexts.propagatingRunnable(action, parentContext,
null, deadlinenanos));
}
@Override
public CompletableFuture runAfterBothAsync(final CompletionStage> other,
final Runnable action, final Executor executor) {
return super.runAfterBothAsync(other, ExecutionContexts.propagatingRunnable(action, parentContext,
null, deadlinenanos), executor);
}
@Override
public CompletableFuture applyToEither(final CompletionStage extends T> other,
final Function super T, U> fn) {
return super.applyToEither(other,
ExecutionContexts.propagatingFunction(fn, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture applyToEitherAsync(final CompletionStage extends T> other,
final Function super T, U> fn) {
return super.applyToEitherAsync(other,
ExecutionContexts.propagatingFunction(fn, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture applyToEitherAsync(final CompletionStage extends T> other,
final Function super T, U> fn, final Executor executor) {
return super.applyToEitherAsync(other,
ExecutionContexts.propagatingFunction(fn, parentContext, null, deadlinenanos), executor);
}
@Override
public CompletableFuture acceptEither(final CompletionStage extends T> other,
final Consumer super T> action) {
return super.acceptEither(other,
ExecutionContexts.propagatingConsumer(action, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture acceptEitherAsync(final CompletionStage extends T> other,
final Consumer super T> action) {
return super.acceptEitherAsync(other,
ExecutionContexts.propagatingConsumer(action, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture acceptEitherAsync(final CompletionStage extends T> other,
final Consumer super T> action, final Executor executor) {
return super.acceptEitherAsync(other,
ExecutionContexts.propagatingConsumer(action, parentContext, null, deadlinenanos), executor);
}
@Override
public CompletableFuture runAfterEither(final CompletionStage> other, final Runnable action) {
return super.runAfterEither(other,
ExecutionContexts.propagatingRunnable(action, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture runAfterEitherAsync(final CompletionStage> other, final Runnable action) {
return super.runAfterEitherAsync(other,
ExecutionContexts.propagatingRunnable(action, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture runAfterEitherAsync(final CompletionStage> other,
final Runnable action, final Executor executor) {
return super.runAfterEitherAsync(other,
ExecutionContexts.propagatingRunnable(action, parentContext, null, deadlinenanos), executor);
}
@Override
public CompletableFuture thenCompose(final Function super T, ? extends CompletionStage> fn) {
return super.thenCompose(ExecutionContexts.propagatingFunction(fn, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture thenComposeAsync(final Function super T, ? extends CompletionStage> fn) {
return super.thenComposeAsync(ExecutionContexts.propagatingFunction(fn, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture thenComposeAsync(final Function super T, ? extends CompletionStage> fn,
final Executor executor) {
return super.thenComposeAsync(
ExecutionContexts.propagatingFunction(fn, parentContext, null, deadlinenanos), executor);
}
@Override
public CompletableFuture exceptionally(final Function fn) {
return super.exceptionally(ExecutionContexts.propagatingFunction(fn, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture whenComplete(final BiConsumer super T, ? super Throwable> action) {
return super.whenComplete(ExecutionContexts.propagatingBiConsumer(action, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture whenCompleteAsync(final BiConsumer super T, ? super Throwable> action) {
return super.whenCompleteAsync(
ExecutionContexts.propagatingBiConsumer(action, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture whenCompleteAsync(final BiConsumer super T, ? super Throwable> action,
final Executor executor) {
return super.whenCompleteAsync(
ExecutionContexts.propagatingBiConsumer(action, parentContext, null, deadlinenanos),
executor);
}
@Override
public CompletableFuture handle(final BiFunction super T, Throwable, ? extends U> fn) {
return super.handle(ExecutionContexts.propagatingBiFunction(fn, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture handleAsync(final BiFunction super T, Throwable, ? extends U> fn) {
return super.handleAsync(
ExecutionContexts.propagatingBiFunction(fn, parentContext, null, deadlinenanos));
}
@Override
public CompletableFuture handleAsync(final BiFunction super T, Throwable, ? extends U> fn,
final Executor executor) {
return super.handleAsync(
ExecutionContexts.propagatingBiFunction(fn, parentContext, null, deadlinenanos), executor);
}
@Override
public CompletableFuture toCompletableFuture() {
return this;
}
@Override
public String toString() {
return "ContextPropagatingCompletableFuture{" + "parentContext=" + parentContext
+ ", deadlinenanos=" + deadlinenanos + ", super=" + super.toString() + '}';
}
@Override
@Nullable
public T get() throws InterruptedException, ExecutionException {
try {
long timeout = deadlinenanos - TimeSource.nanoTime();
if (timeout < 0) {
throw new UncheckedTimeoutException("deadline exceeded " + Timing.getCurrentTiming()
.fromNanoTimeToInstant(deadlinenanos));
}
return super.get(timeout, TimeUnit.NANOSECONDS);
} catch (TimeoutException ex) {
throw new UncheckedTimeoutException(ex);
}
}
/**
* JDK 11.
*/
public CompletableFuture completeAsync(final Supplier extends T> supplier) {
try {
return (CompletableFuture)
this.getClass().getMethod("completeAsync", new Class[] {Supplier.class})
.invoke(this, ExecutionContexts.propagatingSupplier(supplier, parentContext, null, deadlinenanos));
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | InvocationTargetException ex) {
throw new UnsupportedOperationException("Supported only on JDK 11", ex);
}
}
/**
* JDK 11.
*/
public CompletableFuture completeAsync(final Supplier extends T> supplier, final Executor executor) {
try {
return (CompletableFuture)
this.getClass().getMethod("completeAsync", new Class[] {Supplier.class, Executor.class})
.invoke(this,
ExecutionContexts.propagatingSupplier(supplier, parentContext, null, deadlinenanos),
executor);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | InvocationTargetException ex) {
throw new UnsupportedOperationException("Supported only on JDK 11", ex);
}
}
/**
* JDK 11!
*/
public CompletableFuture newIncompleteFuture() {
return new ContextPropagatingCompletableFuture<>(parentContext, deadlinenanos);
}
public static CompletableFuture supplyAsync(final Supplier f) {
return supplyAsync(f, DefaultExecutor.INSTANCE);
}
public static CompletableFuture supplyAsync(final Supplier f, final Executor e) {
ExecutionContext current = ExecutionContexts.current();
if (current == null) {
return CompletableFuture.supplyAsync(f, e);
}
return supplyAsync(f, current, e, current.getDeadlineNanos());
}
public static CompletableFuture supplyAsync(
final Supplier f, final Executor e, final long deadlineNanos) {
ExecutionContext current = ExecutionContexts.current();
if (current == null) {
return CompletableFuture.supplyAsync(f, e);
}
return supplyAsync(f, current, e, deadlineNanos);
}
public static CompletableFuture supplyAsync(final Supplier f,
final ExecutionContext current,
final Executor e, final long deadlineNanos) {
long ctxDeadlineNanos = current.getDeadlineNanos();
long currentTime = TimeSource.nanoTime();
long effectiveDeadlineNanos;
if ((ctxDeadlineNanos - currentTime) > (deadlineNanos - currentTime)) {
effectiveDeadlineNanos = deadlineNanos;
} else {
effectiveDeadlineNanos = ctxDeadlineNanos;
}
ContextPropagatingCompletableFuture d
= new ContextPropagatingCompletableFuture(current, effectiveDeadlineNanos);
e.execute(() -> {
try {
U r;
try (ExecutionContext ec = ExecutionContexts.start(f.toString(), current,
currentTime, effectiveDeadlineNanos)) {
r = f.get();
}
d.complete(r);
} catch (Throwable t) {
d.completeExceptionally(t);
}
});
return d;
}
public static CompletableFuture completedFuture(final U value) {
ExecutionContext current = ExecutionContexts.current();
if (current == null) {
return CompletableFuture.completedFuture(value);
} else {
return completedFuture(current, current.getDeadlineNanos(), value);
}
}
public static CompletableFuture completedFuture(
final ExecutionContext parentContext, final long deadlinenanos, final U value) {
ContextPropagatingCompletableFuture r = new ContextPropagatingCompletableFuture(parentContext, deadlinenanos);
if (!r.complete(value)) {
throw new IllegalStateException("Cannot be already completed " + r);
}
return r;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy