package tc.oc.commons.core.concurrent; import java.util.concurrent.Executor; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import tc.oc.commons.core.util.SystemFutureCallback; import tc.oc.commons.core.util.ThrowingConsumer; /** * A decorator for {@link Executor} that adds various convenience methods. */ public interface Flexecutor extends Executor { /** * Decorate the given {@link Executor}, or return it if it is already a {@link Flexecutor}. */ static Flexecutor from(Executor executor) { if(executor instanceof Flexecutor) { return (Flexecutor) executor; } else { return executor::execute; } } /** * Register the given {@link FutureCallback} to be executed through this executor when the given future completes. */ default <T> void callback(ListenableFuture<T> future, FutureCallback<T> callback) { Futures.addCallback(future, callback, this); } /** * Register the given {@link ThrowingConsumer} to be executed through this executor when the given future completes. * * The consumer is wrapped in a {@link SystemFutureCallback}, which handles exceptions from both the future and the consumer. */ default <T> void callback(ListenableFuture<T> future, ThrowingConsumer<T, Exception> consumer) { callback(future, SystemFutureCallback.onSuccess(consumer)); } default Runnable wrap(Runnable task) { return () -> execute(task); } }