Created
January 14, 2018 16:55
-
-
Save yury-kislaik/f143adb78516b9c97f4808e4305953e3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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