
io.atomix.copycat.client.util.OrderedCompletableFuture Maven / Gradle / Ivy
package io.atomix.copycat.client.util;
import io.atomix.catalyst.concurrent.Futures;
import java.util.LinkedList;
import java.util.Queue;
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;
/**
* A {@link CompletableFuture} that ensures callbacks are called in FIFO order.
*
* The default {@link CompletableFuture} does not guarantee the ordering of callbacks, and indeed appears to
* execute them in LIFO order.
*/
public class OrderedCompletableFuture extends CompletableFuture {
private final Queue> orderedFutures = new LinkedList<>();
private boolean complete;
private T result;
private Throwable error;
public OrderedCompletableFuture() {
super.whenComplete(this::complete);
}
/**
* Adds a new ordered future.
*/
private CompletableFuture orderedFuture() {
synchronized (orderedFutures) {
if (complete) {
if (error == null) {
return CompletableFuture.completedFuture(result);
} else {
return Futures.exceptionalFuture(error);
}
} else {
CompletableFuture future = new CompletableFuture<>();
orderedFutures.add(future);
return future;
}
}
}
/**
* Completes futures in FIFO order.
*/
private void complete(T result, Throwable error) {
synchronized (orderedFutures) {
this.complete = true;
this.result = result;
this.error = error;
if (error == null) {
for (CompletableFuture future : orderedFutures) {
future.complete(result);
}
} else {
for (CompletableFuture future : orderedFutures) {
future.completeExceptionally(error);
}
}
}
}
@Override
public CompletableFuture thenApply(Function super T, ? extends U> fn) {
return orderedFuture().thenApply(fn);
}
@Override
public CompletableFuture thenApplyAsync(Function super T, ? extends U> fn) {
return orderedFuture().thenApplyAsync(fn);
}
@Override
public CompletableFuture thenApplyAsync(Function super T, ? extends U> fn, Executor executor) {
return orderedFuture().thenApplyAsync(fn, executor);
}
@Override
public CompletableFuture thenAccept(Consumer super T> action) {
return orderedFuture().thenAccept(action);
}
@Override
public CompletableFuture thenAcceptAsync(Consumer super T> action) {
return orderedFuture().thenAcceptAsync(action);
}
@Override
public CompletableFuture thenAcceptAsync(Consumer super T> action, Executor executor) {
return orderedFuture().thenAcceptAsync(action, executor);
}
@Override
public CompletableFuture thenRun(Runnable action) {
return orderedFuture().thenRun(action);
}
@Override
public CompletableFuture thenRunAsync(Runnable action) {
return orderedFuture().thenRunAsync(action);
}
@Override
public CompletableFuture thenRunAsync(Runnable action, Executor executor) {
return orderedFuture().thenRunAsync(action, executor);
}
@Override
public CompletableFuture thenCombine(CompletionStage extends U> other, BiFunction super T, ? super U, ? extends V> fn) {
return orderedFuture().thenCombine(other, fn);
}
@Override
public CompletableFuture thenCombineAsync(CompletionStage extends U> other, BiFunction super T, ? super U, ? extends V> fn) {
return orderedFuture().thenCombineAsync(other, fn);
}
@Override
public CompletableFuture thenCombineAsync(CompletionStage extends U> other, BiFunction super T, ? super U, ? extends V> fn, Executor executor) {
return orderedFuture().thenCombineAsync(other, fn, executor);
}
@Override
public CompletableFuture thenAcceptBoth(CompletionStage extends U> other, BiConsumer super T, ? super U> action) {
return orderedFuture().thenAcceptBoth(other, action);
}
@Override
public CompletableFuture thenAcceptBothAsync(CompletionStage extends U> other, BiConsumer super T, ? super U> action) {
return orderedFuture().thenAcceptBothAsync(other, action);
}
@Override
public CompletableFuture thenAcceptBothAsync(CompletionStage extends U> other, BiConsumer super T, ? super U> action, Executor executor) {
return orderedFuture().thenAcceptBothAsync(other, action, executor);
}
@Override
public CompletableFuture runAfterBoth(CompletionStage> other, Runnable action) {
return orderedFuture().runAfterBoth(other, action);
}
@Override
public CompletableFuture runAfterBothAsync(CompletionStage> other, Runnable action) {
return orderedFuture().runAfterBothAsync(other, action);
}
@Override
public CompletableFuture runAfterBothAsync(CompletionStage> other, Runnable action, Executor executor) {
return orderedFuture().runAfterBothAsync(other, action, executor);
}
@Override
public CompletableFuture applyToEither(CompletionStage extends T> other, Function super T, U> fn) {
return orderedFuture().applyToEither(other, fn);
}
@Override
public CompletableFuture applyToEitherAsync(CompletionStage extends T> other, Function super T, U> fn) {
return orderedFuture().applyToEitherAsync(other, fn);
}
@Override
public CompletableFuture applyToEitherAsync(CompletionStage extends T> other, Function super T, U> fn, Executor executor) {
return orderedFuture().applyToEitherAsync(other, fn, executor);
}
@Override
public CompletableFuture acceptEither(CompletionStage extends T> other, Consumer super T> action) {
return orderedFuture().acceptEither(other, action);
}
@Override
public CompletableFuture acceptEitherAsync(CompletionStage extends T> other, Consumer super T> action) {
return orderedFuture().acceptEitherAsync(other, action);
}
@Override
public CompletableFuture acceptEitherAsync(CompletionStage extends T> other, Consumer super T> action, Executor executor) {
return orderedFuture().acceptEitherAsync(other, action, executor);
}
@Override
public CompletableFuture runAfterEither(CompletionStage> other, Runnable action) {
return orderedFuture().runAfterEither(other, action);
}
@Override
public CompletableFuture runAfterEitherAsync(CompletionStage> other, Runnable action) {
return orderedFuture().runAfterEitherAsync(other, action);
}
@Override
public CompletableFuture runAfterEitherAsync(CompletionStage> other, Runnable action, Executor executor) {
return orderedFuture().runAfterEitherAsync(other, action, executor);
}
@Override
public CompletableFuture thenCompose(Function super T, ? extends CompletionStage> fn) {
return orderedFuture().thenCompose(fn);
}
@Override
public CompletableFuture thenComposeAsync(Function super T, ? extends CompletionStage> fn) {
return orderedFuture().thenComposeAsync(fn);
}
@Override
public CompletableFuture thenComposeAsync(Function super T, ? extends CompletionStage> fn, Executor executor) {
return orderedFuture().thenComposeAsync(fn, executor);
}
@Override
public CompletableFuture whenComplete(BiConsumer super T, ? super Throwable> action) {
return orderedFuture().whenComplete(action);
}
@Override
public CompletableFuture whenCompleteAsync(BiConsumer super T, ? super Throwable> action) {
return orderedFuture().whenCompleteAsync(action);
}
@Override
public CompletableFuture whenCompleteAsync(BiConsumer super T, ? super Throwable> action, Executor executor) {
return orderedFuture().whenCompleteAsync(action, executor);
}
@Override
public CompletableFuture handle(BiFunction super T, Throwable, ? extends U> fn) {
return orderedFuture().handle(fn);
}
@Override
public CompletableFuture handleAsync(BiFunction super T, Throwable, ? extends U> fn) {
return orderedFuture().handleAsync(fn);
}
@Override
public CompletableFuture handleAsync(BiFunction super T, Throwable, ? extends U> fn, Executor executor) {
return orderedFuture().handleAsync(fn, executor);
}
@Override
public CompletableFuture exceptionally(Function fn) {
return orderedFuture().exceptionally(fn);
}
@Override
public CompletableFuture toCompletableFuture() {
return this;
}
}