package tc.oc.commons.core.concurrent;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListenableFuture;
import tc.oc.commons.core.util.Pair;
import tc.oc.commons.core.util.ThrowingBiConsumer;
/**
* Base implementation for {@link ContextualExecutor}.
*
* Just implement {@link #context()}.
*/
public abstract class AbstractContextualExecutor<C> implements ContextualExecutor<C> {
private final Flexecutor executor;
protected AbstractContextualExecutor(Executor executor) {
this(Flexecutor.from(executor));
}
protected AbstractContextualExecutor(Flexecutor executor) {
this.executor = executor;
}
/**
* Called immediately before executing a task to retrieve the {@link C}
* instance to pass to the task. If null is returned, the task is not run.
*/
protected abstract @Nullable C context();
@Override
public void execute(Consumer<C> task) {
executor.execute(() -> {
final C context = context();
if(context != null) task.accept(context);
});
}
@Override
public <T> void callback(ListenableFuture<T> future, FutureCallback<Pair<C, T>> callback) {
executor.callback(future, new FutureCallback<T>() {
@Override public void onSuccess(@Nullable T result) {
final C context = context();
if(context != null) callback.onSuccess(Pair.create(context, result));
}
@Override public void onFailure(Throwable t) {
callback.onFailure(t);
}
});
}
@Override
public <T> void callback(ListenableFuture<T> future, ThrowingBiConsumer<C, T, Exception> callback) {
executor.callback(future, result -> {
final C context = context();
if(context != null) callback.accept(context, result);
});
}
}