115 lines
4.4 KiB
Java
115 lines
4.4 KiB
Java
package tc.oc.commons.core.concurrent;
|
|
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.concurrent.Executor;
|
|
import java.util.concurrent.Future;
|
|
import java.util.function.Consumer;
|
|
import java.util.function.Function;
|
|
import javax.annotation.Nullable;
|
|
|
|
import com.google.common.base.Throwables;
|
|
import com.google.common.util.concurrent.AsyncFunction;
|
|
import com.google.common.util.concurrent.FutureCallback;
|
|
import com.google.common.util.concurrent.Futures;
|
|
import com.google.common.util.concurrent.ListenableFuture;
|
|
import com.google.common.util.concurrent.MoreExecutors;
|
|
import com.google.common.util.concurrent.Uninterruptibles;
|
|
import tc.oc.commons.core.util.Pair;
|
|
import tc.oc.commons.core.util.ThrowingFunction;
|
|
|
|
public final class FutureUtils {
|
|
private FutureUtils() {}
|
|
|
|
/**
|
|
* Get the result of the given {@link Future}, retrying if interrupted using
|
|
* {@link Uninterruptibles#getUninterruptibly}, and wrap any checked exceptions
|
|
* other than the one given using {@link Throwables#propagate(Throwable)}.
|
|
*
|
|
* Use this when you only need to handle a particular checked exception,
|
|
* and want any others can be handled generically.
|
|
*/
|
|
public static <T, E extends Throwable> T getUncheckedExcept(Future<T> future, Class<E> except) throws E {
|
|
try {
|
|
return Uninterruptibles.getUninterruptibly(future);
|
|
} catch(ExecutionException e) {
|
|
if(except.isInstance(e.getCause())) {
|
|
throw except.cast(e.getCause());
|
|
} else {
|
|
throw Throwables.propagate(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static <T> FutureCallback<T> successCallback(Consumer<T> consumer) {
|
|
return new SuccessCallback<>(consumer);
|
|
}
|
|
|
|
public static <T> FutureCallback<T> failureCallback(Consumer<Throwable> consumer) {
|
|
return new FailureCallback<>(consumer);
|
|
}
|
|
|
|
public static <T> void onSuccess(ListenableFuture<T> future, Consumer<T> callback) {
|
|
Futures.addCallback(future, successCallback(callback));
|
|
}
|
|
|
|
public static <T> void onSuccess(ListenableFuture<T> future, Consumer<T> callback, @Nullable Executor executor) {
|
|
if(executor != null) {
|
|
Futures.addCallback(future, successCallback(callback), executor);
|
|
} else {
|
|
onSuccess(future, callback);
|
|
}
|
|
}
|
|
|
|
public static <T> void onFailure(ListenableFuture<T> future, Consumer<Throwable> callback) {
|
|
Futures.addCallback(future, failureCallback(callback));
|
|
}
|
|
|
|
public static <T> void onFailure(ListenableFuture<T> future, Consumer<Throwable> callback, @Nullable Executor executor) {
|
|
if(executor != null) {
|
|
Futures.addCallback(future, failureCallback(callback), executor);
|
|
} else {
|
|
onFailure(future, callback);
|
|
}
|
|
}
|
|
|
|
public static <T> ListenableFuture<T> peek(ListenableFuture<T> future, Consumer<T> callback) {
|
|
return peek(future, callback, MoreExecutors.sameThreadExecutor());
|
|
}
|
|
|
|
public static <T> ListenableFuture<T> peek(ListenableFuture<T> future, Consumer<T> callback, Executor executor) {
|
|
return Futures.transform(future, (com.google.common.base.Function<T, T>) t -> {
|
|
callback.accept(t);
|
|
return t;
|
|
}, executor);
|
|
}
|
|
|
|
/**
|
|
* Equivalent to {@link Futures#transform}, but can be passed a lambda unambiguously
|
|
*/
|
|
public static <T, R> ListenableFuture<R> mapSync(ListenableFuture<T> in, ThrowingFunction<T, R, ?> op) {
|
|
return mapSync(in, op, MoreExecutors.sameThreadExecutor());
|
|
}
|
|
|
|
public static <T, R> ListenableFuture<R> mapSync(ListenableFuture<T> in, ThrowingFunction<T, R, ?> op, Executor executor) {
|
|
return mapAsync(in, out -> {
|
|
try {
|
|
return Futures.immediateFuture(op.applyThrows(out));
|
|
} catch(Throwable ex) {
|
|
return Futures.immediateFailedFuture(ex);
|
|
}
|
|
}, executor);
|
|
}
|
|
|
|
public static <T, R> ListenableFuture<R> mapAsync(ListenableFuture<T> in, AsyncFunction<T, R> op) {
|
|
return Futures.transform(in, op);
|
|
}
|
|
|
|
public static <T, R> ListenableFuture<R> mapAsync(ListenableFuture<T> in, AsyncFunction<T, R> op, Executor executor) {
|
|
return Futures.transform(in, op, executor);
|
|
}
|
|
|
|
public static <A, B> ListenableFuture<Pair<A, B>> pair(ListenableFuture<A> a, ListenableFuture<B> b) {
|
|
return mapSync(Futures.allAsList(a, b), list -> Pair.of((A) list.get(0), (B) list.get(1)));
|
|
}
|
|
}
|