package io.airlift.concurrent; import com.google.common.annotations.VisibleForTesting; import com.google.common.util.concurrent.AbstractFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import javax.annotation.Nullable; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; public final class ExtendedSettableFuture<V> extends AbstractFuture<V> { public static <V> ExtendedSettableFuture<V> create() { return new ExtendedSettableFuture<>(); } private ExtendedSettableFuture() {} @Override public boolean set(@Nullable V value) { return super.set(value); } @Override public boolean setException(Throwable throwable) { return super.setException(throwable); } /** * Sets this current future with the result of the delegate. * <p> * Values and exceptions are both propagated to this Future. * If this Future is cancelled, than the delegate will also be cancelled * with the same interrupt flag. */ public void setAsync(ListenableFuture<? extends V> delegate) { Futures.addCallback(delegate, new FutureCallback<V>() { @Override public void onSuccess(@Nullable V result) { set(result); } @Override public void onFailure(Throwable t) { setException(t); } }); super.addListener(() -> { if (super.isCancelled()) { delegate.cancel(super.wasInterrupted()); } }, directExecutor()); } /** * @return true if the Future was interrupted when cancelled. */ @VisibleForTesting boolean checkWasInterrupted() { return super.wasInterrupted(); } }