Skip to content

Instantly share code, notes, and snippets.

@yury-kislaik
Created January 14, 2018 16:55
Show Gist options
  • Save yury-kislaik/f143adb78516b9c97f4808e4305953e3 to your computer and use it in GitHub Desktop.
Save yury-kislaik/f143adb78516b9c97f4808e4305953e3 to your computer and use it in GitHub Desktop.
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 play.libs.concurrent.HttpExecutionContext;
/**
* Decorator, which allows to preserve HttpExecutionContext between async callbacks, without passing it explicitly.
*
* @param <T> any type.
*/
public class ContextPreservingCompletionStage<T> implements CompletionStage<T> {
private HttpExecutionContext context;
private CompletionStage<T> delegate;
public ContextPreservingCompletionStage(CompletionStage<T> delegate, HttpExecutionContext context) {
this.delegate = delegate;
this.context = context;
}
@Override
public <U> CompletionStage<U> thenApply(Function<? super T, ? extends U> fn) {
return thenApplyAsync(fn);
}
@Override
public <U> CompletionStage<U> thenApplyAsync(Function<? super T, ? extends U> fn) {
return thenApplyAsync(fn, context.current());
}
@Override
public <U> CompletionStage<U> thenApplyAsync(Function<? super T, ? extends U> fn, Executor executor) {
return new ContextPreservingCompletionStage<>(delegate.thenApplyAsync(fn, executor), context);
}
@Override
public CompletionStage<Void> thenAccept(Consumer<? super T> action) {
return thenAcceptAsync(action);
}
@Override
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action) {
return thenAcceptAsync(action, context.current());
}
@Override
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor) {
return new ContextPreservingCompletionStage<>(delegate.thenAcceptAsync(action, executor), context);
}
@Override
public CompletionStage<Void> thenRun(Runnable action) {
return thenRunAsync(action);
}
@Override
public CompletionStage<Void> thenRunAsync(Runnable action) {
return thenRunAsync(action, context.current());
}
@Override
public CompletionStage<Void> thenRunAsync(Runnable action, Executor executor) {
return new ContextPreservingCompletionStage<Void>(delegate.thenRunAsync(action, executor), context);
}
@Override
public <U, V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn) {
return thenCombineAsync(other, fn);
}
@Override
public <U, V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn) {
return thenCombineAsync(other, fn, context.current());
}
@Override
public <U, V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn, Executor executor) {
return new ContextPreservingCompletionStage<V>(delegate.thenCombineAsync(other, fn, executor), context);
}
@Override
public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action) {
return thenAcceptBothAsync(other, action);
}
@Override
public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action) {
return thenAcceptBothAsync(other, action, context.current());
}
@Override
public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action, Executor executor) {
return new ContextPreservingCompletionStage<>(delegate.thenAcceptBothAsync(other, action, executor), context);
}
@Override
public CompletionStage<Void> runAfterBoth(CompletionStage<?> other, Runnable action) {
return runAfterBothAsync(other, action);
}
@Override
public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action) {
return runAfterBothAsync(other, action, context.current());
}
@Override
public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action, Executor executor) {
return new ContextPreservingCompletionStage<>(delegate.runAfterBothAsync(other, action, executor), context);
}
@Override
public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn) {
return applyToEitherAsync(other, fn);
}
@Override
public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn) {
return applyToEitherAsync(other, fn, context.current());
}
@Override
public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn, Executor executor) {
return new ContextPreservingCompletionStage<U>(delegate.applyToEitherAsync(other, fn, executor), context);
}
@Override
public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action) {
return acceptEitherAsync(other, action);
}
@Override
public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action) {
return acceptEitherAsync(other, action, context.current());
}
@Override
public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor) {
return new ContextPreservingCompletionStage<>(delegate.acceptEitherAsync(other, action, executor), context);
}
@Override
public CompletionStage<Void> runAfterEither(CompletionStage<?> other, Runnable action) {
return runAfterEitherAsync(other, action);
}
@Override
public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action) {
return runAfterEitherAsync(other, action, context.current());
}
@Override
public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action, Executor executor) {
return new ContextPreservingCompletionStage<>(delegate.runAfterEitherAsync(other, action, executor), context);
}
@Override
public <U> CompletionStage<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) {
return thenComposeAsync(fn);
}
@Override
public <U> CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) {
return thenComposeAsync(fn, context.current());
}
@Override
public <U> CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor) {
return new ContextPreservingCompletionStage<U>(delegate.thenComposeAsync(fn, executor), context);
}
@Override
public CompletionStage<T> exceptionally(Function<Throwable, ? extends T> fn) {
// There is no async version of `exceptionally`, so we apply 'handle' instead.
return handle((result, error) -> (result == null) ? fn.apply(error) : result);
}
@Override
public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) {
return whenCompleteAsync(action);
}
@Override
public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action) {
return whenCompleteAsync(action, context.current());
}
@Override
public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor) {
return new ContextPreservingCompletionStage<T>(delegate.whenCompleteAsync(action, executor), context);
}
@Override
public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn) {
return handleAsync(fn);
}
@Override
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn) {
return handleAsync(fn, context.current());
}
@Override
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {
return new ContextPreservingCompletionStage<U>(delegate.handleAsync(fn, executor), context);
}
/**
* Use with caution. Returned instance will not be bound to HttpExecutionContext.
* Ues only when you need get() or join() methods.
*
* @return unwrapped CompletionStage instance.
*/
@Override
public CompletableFuture<T> toCompletableFuture() {
return delegate.toCompletableFuture();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment