com.fireflysource.common.concurrent.CompletableFutures Maven / Gradle / Ivy
package com.fireflysource.common.concurrent;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
abstract public class CompletableFutures {
/**
* Returns a new stage that, when this stage completes
* exceptionally, is executed with this stage's exception as the
* argument to the supplied function. Otherwise, if this stage
* completes normally, then the returned stage also completes
* normally with the same value.
*
* This differs from
* {@link java.util.concurrent.CompletionStage#exceptionally(java.util.function.Function)}
* in that the function should return a {@link java.util.concurrent.CompletionStage} rather than
* the value directly.
*
* @param stage the {@link CompletionStage} to compose
* @param fn the function computes the value of the
* returned {@link CompletionStage} if this stage completed
* exceptionally
* @param the type of the input stage's value.
* @return the new {@link CompletionStage}
*/
public static CompletionStage exceptionallyCompose(CompletionStage stage, Function> fn) {
return dereference(wrap(stage).exceptionally(fn));
}
public static CompletionStage dereference(CompletionStage extends CompletionStage> stage) {
return stage.thenCompose(Function.identity());
}
private static CompletionStage> wrap(CompletionStage future) {
return future.thenApply(CompletableFuture::completedFuture);
}
/**
* Create a failed future.
*
* @param t The exception.
* @param The future result type.
* @return The failed future.
*/
public static CompletableFuture failedFuture(Throwable t) {
CompletableFuture future = new CompletableFuture<>();
future.completeExceptionally(t);
return future;
}
/**
* Retry the async operation.
*
* @param retryCount The max retry times.
* @param supplier The async operation function.
* @param beforeRetry The callback before retries async operation.
* @param The future result type.
* @return The operation result future.
*/
public static CompletableFuture retry(int retryCount, Supplier> supplier, BiConsumer beforeRetry) {
return exceptionallyCompose(supplier.get(), e -> {
if (retryCount > 0) {
beforeRetry.accept(e, retryCount);
return retry(retryCount - 1, supplier, beforeRetry);
} else {
return failedFuture(e);
}
}).toCompletableFuture();
}
public static CompletableFuture doFinally(CompletionStage stage, BiFunction> function) {
CompletableFuture future = new CompletableFuture<>();
stage.handle((value, throwable) -> {
function.apply(value, throwable).handle((v, t) -> {
if (throwable != null) {
future.completeExceptionally(throwable);
} else {
future.complete(value);
}
return v;
});
return value;
});
return future;
}
}