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.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> 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 prepareRetry 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 prepareRetry) {
return exceptionallyCompose(supplier.get(), e -> {
if (retryCount > 0) {
prepareRetry.accept(e, retryCount);
return retry(retryCount - 1, supplier, prepareRetry);
} else {
return failedFuture(e);
}
}).toCompletableFuture();
}
}