package java.util.concurrent; import jsinterop.annotations.*; import java.util.*; import java.util.function.*; /** Emulation of CompletableFuture * */ public class CompletableFuture<T> implements Future<T>, CompletionStage<T> { public static <T> CompletableFuture<T> completedFuture(T value) { return new CompletableFuture<T>(value); } // holders for all the possible consumers of this future private final List<Consumer<? super T>> consumers = new ArrayList<>(); private final List<CompletableFuture<Void>> consumeFutures = new ArrayList<>(); private final List<Function<? super T, ? extends Object>> applies = new ArrayList<>(); private final List<CompletableFuture> applyFutures = new ArrayList<>(); private final List<Function<? super T, ? extends CompletionStage<? extends Object>>> composers = new ArrayList<>(); private final List<CompletableFuture<? extends Object>> composeFutures = new ArrayList<>(); private final List<Function<? super Throwable, ? extends T>> errors = new ArrayList<>(); private final List<CompletableFuture<T>> errorFutures = new ArrayList<>(); private T value; private Throwable reason; private boolean isDone; private CompletableFuture(T value, Throwable err, boolean isDone) { this.value = value; this.reason = err; this.isDone = isDone; } public CompletableFuture() { this(null, null, false); } private CompletableFuture(T value) { this(value, null, true); } private CompletableFuture(Throwable err) { this(null, err, true); } @Override @JsMethod public <U> CompletableFuture<U> thenApply(Function<? super T, ? extends U> fn) { CompletableFuture<U> fut = new CompletableFuture<>(); if (isDone()) { if (reason != null) { fut.completeExceptionally(reason); } else { try { fut.complete(fn.apply(value)); } catch(Throwable t) { fut.completeExceptionally(t); } } } else { applyFutures.add(fut); applies.add(fn); } return fut; } @Override public CompletableFuture<Void> thenAccept(Consumer<? super T> action) { CompletableFuture<Void> fut = new CompletableFuture<>(); if (isDone()) { if (reason != null) { fut.completeExceptionally(reason); } else { try { action.accept(value); fut.complete(null); } catch(Throwable t) { fut.completeExceptionally(t); } } } else { consumeFutures.add(fut); consumers.add(action); } return fut; } @Override public <U, V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn) { throw new IllegalStateException("Unimplemented!"); } @Override @JsMethod public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) { CompletableFuture<U> fut = new CompletableFuture<>(); if (isDone()) { if (reason != null) { fut.completeExceptionally(reason); } else { try { fn.apply(value) .thenAccept(fut::complete) .exceptionally(t -> { fut.completeExceptionally(t); return null; }); } catch(Throwable t) { fut.completeExceptionally(t); } } } else { composeFutures.add(fut); composers.add(fn); } return fut; } @JsMethod public boolean complete(T value) { this.value = value; this.isDone = true; for (int i=0; i < applies.size(); i++) { Function<? super T, ? extends Object> function = applies.get(i); CompletableFuture future = applyFutures.get(i); try { future.complete(function.apply(value)); } catch (Throwable t) { future.completeExceptionally(t); } } for (int i=0; i < consumers.size(); i++) { Consumer<? super T> function = consumers.get(i); CompletableFuture<Void> future = consumeFutures.get(i); try { function.accept(value); future.complete(null); } catch (Throwable t) { future.completeExceptionally(t); } } for (int i=0; i < composers.size(); i++) { Function<? super T, ? extends CompletionStage> function = composers.get(i); CompletableFuture future = composeFutures.get(i); try { function.apply(value) .thenAccept(val -> future.complete(val)) .exceptionally(t -> { future.completeExceptionally((Throwable) t); return null; }); } catch (Throwable t) { future.completeExceptionally(t); } } for (int i=0; i < errors.size(); i++) { CompletableFuture<T> future = errorFutures.get(i); Function<? super Throwable, ? extends T> function = errors.get(i); try { future.complete(value); } catch (Throwable t) { future.completeExceptionally(t); } } errors.clear(); errorFutures.clear(); composers.clear(); composeFutures.clear(); consumers.clear(); consumeFutures.clear(); applies.clear(); applyFutures.clear(); return true; } @JsMethod public boolean completeExceptionally(Throwable err) { this.reason = err; this.isDone = true; for (int i=0; i < applies.size(); i++) { CompletableFuture future = applyFutures.get(i); try { future.completeExceptionally(err); } catch (Throwable t) { future.completeExceptionally(t); } } for (int i=0; i < consumers.size(); i++) { CompletableFuture<Void> future = consumeFutures.get(i); try { future.completeExceptionally(err); } catch (Throwable t) { future.completeExceptionally(t); } } for (int i=0; i < composers.size(); i++) { CompletableFuture future = composeFutures.get(i); try { future.completeExceptionally(err); } catch (Throwable t) { future.completeExceptionally(t); } } for (int i=0; i < errors.size(); i++) { CompletableFuture<T> future = errorFutures.get(i); Function<? super Throwable, ? extends T> function = errors.get(i); try { future.complete(function.apply(err)); } catch (Throwable t) { future.completeExceptionally(t); } } errors.clear(); errorFutures.clear(); composers.clear(); composeFutures.clear(); consumers.clear(); consumeFutures.clear(); applies.clear(); applyFutures.clear(); return true; } @Override public boolean isDone() { return isDone; } @Override public boolean isCancelled() { throw new IllegalStateException("Unimplemented!"); } @Override public boolean cancel(boolean cancel) { throw new IllegalStateException("Unimplemented!"); } @Override public CompletableFuture<T> toCompletableFuture() { return this; } @Override @JsMethod public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> handler) { if (isDone()) { if (isCompletedExceptionally()) { try { return CompletableFuture.completedFuture(handler.apply(reason)); } catch (Throwable t) { CompletableFuture<T> fut = new CompletableFuture<>(); fut.completeExceptionally(t); return fut; } } else { // no exception occured just return the already completed future return this; } } else { CompletableFuture<T> fut = new CompletableFuture<>(); errorFutures.add(fut); errors.add(handler); return fut; } } public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(Supplier<U> var0, Executor var1) { throw new IllegalStateException("Not implemented!"); } @Override public T get(long t, TimeUnit unit) { throw new IllegalStateException("Not possible to call synchronous get() in JS!"); } @Override public T get() { throw new IllegalStateException("Not possible to call synchronous get() in JS!"); } public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> thenRun(Runnable action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> thenRunAsync(Runnable action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> thenRunAsync(Runnable action, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn) { throw new IllegalStateException("Unimplemented!"); } public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> runAfterBoth(CompletionStage<?> other, Runnable action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> runAfterEither(CompletionStage<?> other, Runnable action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action) { throw new IllegalStateException("Unimplemented!"); } public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn) { throw new IllegalStateException("Unimplemented!"); } public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) { throw new IllegalStateException("Unimplemented!"); } public boolean isCompletedExceptionally() { return isDone() && reason != null; } }