com.google.common.util.concurrent.Futures Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*
* Copyright (C) 2006 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.util.concurrent;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly;
import static java.lang.Thread.currentThread;
import static java.util.Arrays.asList;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
/**
* Static utility methods pertaining to the {@link Future} interface.
*
* Many of these methods use the {@link ListenableFuture} API; consult the
* Guava User Guide article on
* {@code ListenableFuture}.
*
* @author Kevin Bourrillion
* @author Nishant Thakkar
* @author Sven Mawson
* @since 1.0
*
* @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
*/
@Beta
@Deprecated(since = "2022-12-01")
public final class Futures {
private Futures() {
}
/**
* Creates a {@link CheckedFuture} out of a normal {@link ListenableFuture}
* and a {@link Function} that maps from {@link Exception} instances into the
* appropriate checked type.
*
*
The given mapping function will be applied to an
* {@link InterruptedException}, a {@link CancellationException}, or an
* {@link ExecutionException}.
* See {@link Future#get()} for details on the exceptions thrown.
*
* @since 9.0 (source-compatible since 1.0)
*/
public static CheckedFuture makeChecked(ListenableFuture future, Function mapper) {
return new MappingCheckedFuture(checkNotNull(future), mapper);
}
// @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
@Deprecated(since = "2022-12-01")
private abstract static class ImmediateFuture implements ListenableFuture {
private static final Logger log = Logger.getLogger(ImmediateFuture.class.getName());
@Override
public void addListener(Runnable listener, Executor executor) {
checkNotNull(listener, "Runnable was null.");
checkNotNull(executor, "Executor was null.");
try {
executor.execute(listener);
} catch (RuntimeException e) {
// ListenableFuture's contract is that it will not throw unchecked
// exceptions, so log the bad runnable and/or executor and swallow it.
log.log(Level.SEVERE, "RuntimeException while executing runnable " + listener + " with executor " + executor, e);
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
@Override
public abstract V get() throws ExecutionException;
@Override
public V get(long timeout, TimeUnit unit) throws ExecutionException {
checkNotNull(unit);
return get();
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return true;
}
}
// @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
@Deprecated(since = "2022-12-01")
private static class ImmediateSuccessfulFuture extends ImmediateFuture {
@Nullable
private final V value;
ImmediateSuccessfulFuture(@Nullable V value) {
this.value = value;
}
@Override
public V get() {
return value;
}
}
// @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
@Deprecated(since = "2022-12-01")
private static class ImmediateSuccessfulCheckedFuture extends ImmediateFuture implements CheckedFuture {
@Nullable
private final V value;
ImmediateSuccessfulCheckedFuture(@Nullable V value) {
this.value = value;
}
@Override
public V get() {
return value;
}
@Override
public V checkedGet() {
return value;
}
@Override
public V checkedGet(long timeout, TimeUnit unit) {
checkNotNull(unit);
return value;
}
}
// @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
@Deprecated(since = "2022-12-01")
private static class ImmediateFailedFuture extends ImmediateFuture {
private final Throwable thrown;
ImmediateFailedFuture(Throwable thrown) {
this.thrown = thrown;
}
@Override
public V get() throws ExecutionException {
throw new ExecutionException(thrown);
}
}
// @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
@Deprecated(since = "2022-12-01")
private static class ImmediateCancelledFuture extends ImmediateFuture {
private final CancellationException thrown;
ImmediateCancelledFuture() {
this.thrown = new CancellationException("Immediate cancelled future.");
}
@Override
public boolean isCancelled() {
return true;
}
@Override
public V get() {
throw AbstractFuture.cancellationExceptionWithCause("Task was cancelled.", thrown);
}
}
// @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
@Deprecated(since = "2022-12-01")
private static class ImmediateFailedCheckedFuture extends ImmediateFuture implements CheckedFuture {
private final X thrown;
ImmediateFailedCheckedFuture(X thrown) {
this.thrown = thrown;
}
@Override
public V get() throws ExecutionException {
throw new ExecutionException(thrown);
}
@Override
public V checkedGet() throws X {
throw thrown;
}
@Override
public V checkedGet(long timeout, TimeUnit unit) throws X {
checkNotNull(unit);
throw thrown;
}
}
/**
* Creates a {@code ListenableFuture} which has its value set immediately upon
* construction. The getters just return the value. This {@code Future} can't
* be canceled or timed out and its {@code isDone()} method always returns
* {@code true}.
*/
public static ListenableFuture immediateFuture(@Nullable V value) {
return new ImmediateSuccessfulFuture(value);
}
/**
* Returns a {@code CheckedFuture} which has its value set immediately upon
* construction.
*
* The returned {@code Future} can't be cancelled, and its {@code isDone()}
* method always returns {@code true}. Calling {@code get()} or {@code
* checkedGet()} will immediately return the provided value.
*/
public static CheckedFuture immediateCheckedFuture(@Nullable V value) {
return new ImmediateSuccessfulCheckedFuture(value);
}
/**
* Returns a {@code ListenableFuture} which has an exception set immediately
* upon construction.
*
* The returned {@code Future} can't be cancelled, and its {@code isDone()}
* method always returns {@code true}. Calling {@code get()} will immediately
* throw the provided {@code Throwable} wrapped in an {@code
* ExecutionException}.
*/
public static ListenableFuture immediateFailedFuture(Throwable throwable) {
checkNotNull(throwable);
return new ImmediateFailedFuture(throwable);
}
/**
* Creates a {@code ListenableFuture} which is cancelled immediately upon
* construction, so that {@code isCancelled()} always returns {@code true}.
*
* @since 14.0
*/
public static ListenableFuture immediateCancelledFuture() {
return new ImmediateCancelledFuture();
}
/**
* Returns a {@code CheckedFuture} which has an exception set immediately upon
* construction.
*
* The returned {@code Future} can't be cancelled, and its {@code isDone()}
* method always returns {@code true}. Calling {@code get()} will immediately
* throw the provided {@code Exception} wrapped in an {@code
* ExecutionException}, and calling {@code checkedGet()} will throw the
* provided exception itself.
*/
public static CheckedFuture immediateFailedCheckedFuture(X exception) {
checkNotNull(exception);
return new ImmediateFailedCheckedFuture(exception);
}
/**
* Returns a {@code Future} whose result is taken from the given primary
* {@code input} or, if the primary input fails, from the {@code Future}
* provided by the {@code fallback}. {@link FutureFallback#create} is not
* invoked until the primary input has failed, so if the primary input
* succeeds, it is never invoked. If, during the invocation of {@code
* fallback}, an exception is thrown, this exception is used as the result of
* the output {@code Future}.
*
* Below is an example of a fallback that returns a default value if an
* exception occurs:
*
*
{@code
* ListenableFuture fetchCounterFuture = ...;
*
* // Falling back to a zero counter in case an exception happens when
* // processing the RPC to fetch counters.
* ListenableFuture faultTolerantFuture = Futures.withFallback(
* fetchCounterFuture, new FutureFallback() {
* public ListenableFuture create(Throwable t) {
* // Returning "0" as the default for the counter when the
* // exception happens.
* return immediateFuture(0);
* }
* });}
*
* The fallback can also choose to propagate the original exception when
* desired:
*
*
{@code
* ListenableFuture fetchCounterFuture = ...;
*
* // Falling back to a zero counter only in case the exception was a
* // TimeoutException.
* ListenableFuture faultTolerantFuture = Futures.withFallback(
* fetchCounterFuture, new FutureFallback() {
* public ListenableFuture create(Throwable t) {
* if (t instanceof TimeoutException) {
* return immediateFuture(0);
* }
* return immediateFailedFuture(t);
* }
* });}
*
* Note: If the derived {@code Future} is slow or heavyweight to create
* (whether the {@code Future} itself is slow or heavyweight to complete is
* irrelevant), consider {@linkplain #withFallback(ListenableFuture,
* FutureFallback, Executor) supplying an executor}. If you do not supply an
* executor, {@code withFallback} will use {@link
* MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some
* caveats for heavier operations. For example, the call to {@code
* fallback.create} may run on an unpredictable or undesirable thread:
*
*
* - If the input {@code Future} is done at the time {@code withFallback}
* is called, {@code withFallback} will call {@code fallback.create} inline.
*
- If the input {@code Future} is not yet done, {@code withFallback} will
* schedule {@code fallback.create} to be run by the thread that completes
* the input {@code Future}, which may be an internal system thread such as
* an RPC network thread.
*
*
* Also note that, regardless of which thread executes the {@code
* sameThreadExecutor} {@code fallback.create}, all other registered but
* unexecuted listeners are prevented from running during its execution, even
* if those listeners are to run in other executors.
*
* @param input the primary input {@code Future}
* @param fallback the {@link FutureFallback} implementation to be called if
* {@code input} fails
* @since 14.0
*/
public static ListenableFuture withFallback(ListenableFuture extends V> input, FutureFallback extends V> fallback) {
return withFallback(input, fallback, sameThreadExecutor());
}
/**
* Returns a {@code Future} whose result is taken from the given primary
* {@code input} or, if the primary input fails, from the {@code Future}
* provided by the {@code fallback}. {@link FutureFallback#create} is not
* invoked until the primary input has failed, so if the primary input
* succeeds, it is never invoked. If, during the invocation of {@code
* fallback}, an exception is thrown, this exception is used as the result of
* the output {@code Future}.
*
* Below is an example of a fallback that returns a default value if an
* exception occurs:
*
*
{@code
* ListenableFuture fetchCounterFuture = ...;
*
* // Falling back to a zero counter in case an exception happens when
* // processing the RPC to fetch counters.
* ListenableFuture faultTolerantFuture = Futures.withFallback(
* fetchCounterFuture, new FutureFallback() {
* public ListenableFuture create(Throwable t) {
* // Returning "0" as the default for the counter when the
* // exception happens.
* return immediateFuture(0);
* }
* }, sameThreadExecutor());}
*
* The fallback can also choose to propagate the original exception when
* desired:
*
*
{@code
* ListenableFuture fetchCounterFuture = ...;
*
* // Falling back to a zero counter only in case the exception was a
* // TimeoutException.
* ListenableFuture faultTolerantFuture = Futures.withFallback(
* fetchCounterFuture, new FutureFallback() {
* public ListenableFuture create(Throwable t) {
* if (t instanceof TimeoutException) {
* return immediateFuture(0);
* }
* return immediateFailedFuture(t);
* }
* }, sameThreadExecutor());}
*
* When the execution of {@code fallback.create} is fast and lightweight
* (though the {@code Future} it returns need not meet these criteria),
* consider {@linkplain #withFallback(ListenableFuture, FutureFallback)
* omitting the executor} or explicitly specifying {@code
* sameThreadExecutor}. However, be aware of the caveats documented in the
* link above.
*
* @param input the primary input {@code Future}
* @param fallback the {@link FutureFallback} implementation to be called if
* {@code input} fails
* @param executor the executor that runs {@code fallback} if {@code input}
* fails
* @since 14.0
*/
public static ListenableFuture withFallback(ListenableFuture extends V> input, FutureFallback extends V> fallback, Executor executor) {
checkNotNull(fallback);
return new FallbackFuture(input, fallback, executor);
}
/**
* A future that falls back on a second, generated future, in case its
* original future fails.
*
* @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
*/
@Deprecated(since = "2022-12-01")
private static class FallbackFuture extends AbstractFuture {
private volatile ListenableFuture extends V> running;
FallbackFuture(ListenableFuture extends V> input, final FutureFallback extends V> fallback, final Executor executor) {
running = input;
addCallback(running, new FutureCallback() {
@Override
public void onSuccess(V value) {
set(value);
}
@Override
public void onFailure(Throwable t) {
if (isCancelled()) {
return;
}
try {
running = fallback.create(t);
if (isCancelled()) {
// in case cancel called in the meantime
running.cancel(wasInterrupted());
return;
}
addCallback(running, new FutureCallback() {
@Override
public void onSuccess(V value) {
set(value);
}
@Override
public void onFailure(Throwable t) {
if (running.isCancelled()) {
cancel(false);
} else {
setException(t);
}
}
}, sameThreadExecutor());
} catch (Throwable e) {
setException(e);
}
}
}, executor);
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (super.cancel(mayInterruptIfRunning)) {
running.cancel(mayInterruptIfRunning);
return true;
}
return false;
}
}
/**
* Returns a new {@code ListenableFuture} whose result is asynchronously
* derived from the result of the given {@code Future}. More precisely, the
* returned {@code Future} takes its result from a {@code Future} produced by
* applying the given {@code AsyncFunction} to the result of the original
* {@code Future}. Example:
*
* {@code
* ListenableFuture rowKeyFuture = indexService.lookUp(query);
* AsyncFunction queryFunction =
* new AsyncFunction() {
* public ListenableFuture apply(RowKey rowKey) {
* return dataService.read(rowKey);
* }
* };
* ListenableFuture queryFuture =
* transform(rowKeyFuture, queryFunction);}
*
* Note: If the derived {@code Future} is slow or heavyweight to create
* (whether the {@code Future} itself is slow or heavyweight to complete is
* irrelevant), consider {@linkplain #transform(ListenableFuture,
* AsyncFunction, Executor) supplying an executor}. If you do not supply an
* executor, {@code transform} will use {@link
* MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some
* caveats for heavier operations. For example, the call to {@code
* function.apply} may run on an unpredictable or undesirable thread:
*
*
* - If the input {@code Future} is done at the time {@code transform} is
* called, {@code transform} will call {@code function.apply} inline.
*
- If the input {@code Future} is not yet done, {@code transform} will
* schedule {@code function.apply} to be run by the thread that completes the
* input {@code Future}, which may be an internal system thread such as an
* RPC network thread.
*
*
* Also note that, regardless of which thread executes the {@code
* sameThreadExecutor} {@code function.apply}, all other registered but
* unexecuted listeners are prevented from running during its execution, even
* if those listeners are to run in other executors.
*
*
The returned {@code Future} attempts to keep its cancellation state in
* sync with that of the input future and that of the future returned by the
* function. That is, if the returned {@code Future} is cancelled, it will
* attempt to cancel the other two, and if either of the other two is
* cancelled, the returned {@code Future} will receive a callback in which it
* will attempt to cancel itself.
*
* @param input The future to transform
* @param function A function to transform the result of the input future
* to the result of the output future
* @return A future that holds result of the function (if the input succeeded)
* or the original input's failure (if not)
* @since 11.0
*/
public static ListenableFuture transform(ListenableFuture input, AsyncFunction super I, ? extends O> function) {
return transform(input, function, MoreExecutors.sameThreadExecutor());
}
/**
* Returns a new {@code ListenableFuture} whose result is asynchronously
* derived from the result of the given {@code Future}. More precisely, the
* returned {@code Future} takes its result from a {@code Future} produced by
* applying the given {@code AsyncFunction} to the result of the original
* {@code Future}. Example:
*
* {@code
* ListenableFuture rowKeyFuture = indexService.lookUp(query);
* AsyncFunction queryFunction =
* new AsyncFunction() {
* public ListenableFuture apply(RowKey rowKey) {
* return dataService.read(rowKey);
* }
* };
* ListenableFuture queryFuture =
* transform(rowKeyFuture, queryFunction, executor);}
*
* The returned {@code Future} attempts to keep its cancellation state in
* sync with that of the input future and that of the future returned by the
* chain function. That is, if the returned {@code Future} is cancelled, it
* will attempt to cancel the other two, and if either of the other two is
* cancelled, the returned {@code Future} will receive a callback in which it
* will attempt to cancel itself.
*
*
When the execution of {@code function.apply} is fast and lightweight
* (though the {@code Future} it returns need not meet these criteria),
* consider {@linkplain #transform(ListenableFuture, AsyncFunction) omitting
* the executor} or explicitly specifying {@code sameThreadExecutor}.
* However, be aware of the caveats documented in the link above.
*
* @param input The future to transform
* @param function A function to transform the result of the input future
* to the result of the output future
* @param executor Executor to run the function in.
* @return A future that holds result of the function (if the input succeeded)
* or the original input's failure (if not)
* @since 11.0
*/
public static ListenableFuture transform(ListenableFuture input, AsyncFunction super I, ? extends O> function, Executor executor) {
ChainingListenableFuture output = new ChainingListenableFuture(function, input);
input.addListener(output, executor);
return output;
}
/**
* Returns a new {@code ListenableFuture} whose result is the product of
* applying the given {@code Function} to the result of the given {@code
* Future}. Example:
*
* {@code
* ListenableFuture queryFuture = ...;
* Function> rowsFunction =
* new Function>() {
* public List apply(QueryResult queryResult) {
* return queryResult.getRows();
* }
* };
* ListenableFuture> rowsFuture =
* transform(queryFuture, rowsFunction);}
*
* Note: If the transformation is slow or heavyweight, consider {@linkplain
* #transform(ListenableFuture, Function, Executor) supplying an executor}.
* If you do not supply an executor, {@code transform} will use {@link
* MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some
* caveats for heavier operations. For example, the call to {@code
* function.apply} may run on an unpredictable or undesirable thread:
*
*
* - If the input {@code Future} is done at the time {@code transform} is
* called, {@code transform} will call {@code function.apply} inline.
*
- If the input {@code Future} is not yet done, {@code transform} will
* schedule {@code function.apply} to be run by the thread that completes the
* input {@code Future}, which may be an internal system thread such as an
* RPC network thread.
*
*
* Also note that, regardless of which thread executes the {@code
* sameThreadExecutor} {@code function.apply}, all other registered but
* unexecuted listeners are prevented from running during its execution, even
* if those listeners are to run in other executors.
*
*
The returned {@code Future} attempts to keep its cancellation state in
* sync with that of the input future. That is, if the returned {@code Future}
* is cancelled, it will attempt to cancel the input, and if the input is
* cancelled, the returned {@code Future} will receive a callback in which it
* will attempt to cancel itself.
*
*
An example use of this method is to convert a serializable object
* returned from an RPC into a POJO.
*
* @param input The future to transform
* @param function A Function to transform the results of the provided future
* to the results of the returned future. This will be run in the thread
* that notifies input it is complete.
* @return A future that holds result of the transformation.
* @since 9.0 (in 1.0 as {@code compose})
*/
public static ListenableFuture transform(ListenableFuture input, final Function super I, ? extends O> function) {
return transform(input, function, MoreExecutors.sameThreadExecutor());
}
/**
* Returns a new {@code ListenableFuture} whose result is the product of
* applying the given {@code Function} to the result of the given {@code
* Future}. Example:
*
* {@code
* ListenableFuture queryFuture = ...;
* Function> rowsFunction =
* new Function>() {
* public List apply(QueryResult queryResult) {
* return queryResult.getRows();
* }
* };
* ListenableFuture> rowsFuture =
* transform(queryFuture, rowsFunction, executor);}
*
* The returned {@code Future} attempts to keep its cancellation state in
* sync with that of the input future. That is, if the returned {@code Future}
* is cancelled, it will attempt to cancel the input, and if the input is
* cancelled, the returned {@code Future} will receive a callback in which it
* will attempt to cancel itself.
*
*
An example use of this method is to convert a serializable object
* returned from an RPC into a POJO.
*
*
When the transformation is fast and lightweight, consider {@linkplain
* #transform(ListenableFuture, Function) omitting the executor} or
* explicitly specifying {@code sameThreadExecutor}. However, be aware of the
* caveats documented in the link above.
*
* @param input The future to transform
* @param function A Function to transform the results of the provided future
* to the results of the returned future.
* @param executor Executor to run the function in.
* @return A future that holds result of the transformation.
* @since 9.0 (in 2.0 as {@code compose})
*/
public static ListenableFuture transform(ListenableFuture input, final Function super I, ? extends O> function, Executor executor) {
checkNotNull(function);
AsyncFunction wrapperFunction = new AsyncFunction() {
@Override
public ListenableFuture apply(I input) {
O output = function.apply(input);
return immediateFuture(output);
}
};
return transform(input, wrapperFunction, executor);
}
/**
* Like {@link #transform(ListenableFuture, Function)} except that the
* transformation {@code function} is invoked on each call to
* {@link Future#get() get()} on the returned future.
*
* The returned {@code Future} reflects the input's cancellation
* state directly, and any attempt to cancel the returned Future is likewise
* passed through to the input Future.
*
*
Note that calls to {@linkplain Future#get(long, TimeUnit) timed get}
* only apply the timeout to the execution of the underlying {@code Future},
* not to the execution of the transformation function.
*
*
The primary audience of this method is callers of {@code transform}
* who don't have a {@code ListenableFuture} available and
* do not mind repeated, lazy function evaluation.
*
* @param input The future to transform
* @param function A Function to transform the results of the provided future
* to the results of the returned future.
* @return A future that returns the result of the transformation.
* @since 10.0
*/
public static Future lazyTransform(final Future input, final Function super I, ? extends O> function) {
checkNotNull(input);
checkNotNull(function);
return new Future() {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return input.cancel(mayInterruptIfRunning);
}
@Override
public boolean isCancelled() {
return input.isCancelled();
}
@Override
public boolean isDone() {
return input.isDone();
}
@Override
public O get() throws InterruptedException, ExecutionException {
return applyTransformation(input.get());
}
@Override
public O get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return applyTransformation(input.get(timeout, unit));
}
private O applyTransformation(I input) throws ExecutionException {
try {
return function.apply(input);
} catch (Throwable t) {
throw new ExecutionException(t);
}
}
};
}
/**
* An implementation of {@code ListenableFuture} that also implements
* {@code Runnable} so that it can be used to nest ListenableFutures.
* Once the passed-in {@code ListenableFuture} is complete, it calls the
* passed-in {@code Function} to generate the result.
*
* If the function throws any checked exceptions, they should be wrapped
* in a {@code UndeclaredThrowableException} so that this class can get
* access to the cause.
*
* @deprecated The Google Guava Core Libraries are deprecated and will not be part of the AEM SDK after April 2023
*/
@Deprecated(since = "2022-12-01")
private static class ChainingListenableFuture extends AbstractFuture implements Runnable {
private AsyncFunction super I, ? extends O> function;
private ListenableFuture extends I> inputFuture;
private volatile ListenableFuture extends O> outputFuture;
private final CountDownLatch outputCreated = new CountDownLatch(1);
private ChainingListenableFuture(AsyncFunction super I, ? extends O> function, ListenableFuture extends I> inputFuture) {
this.function = checkNotNull(function);
this.inputFuture = checkNotNull(inputFuture);
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
/*
* Our additional cancellation work needs to occur even if
* !mayInterruptIfRunning, so we can't move it into interruptTask().
*/
if (super.cancel(mayInterruptIfRunning)) {
// This should never block since only one thread is allowed to cancel
// this Future.
cancel(inputFuture, mayInterruptIfRunning);
cancel(outputFuture, mayInterruptIfRunning);
return true;
}
return false;
}
private void cancel(@Nullable Future> future, boolean mayInterruptIfRunning) {
if (future != null) {
future.cancel(mayInterruptIfRunning);
}
}
@Override
public void run() {
try {
I sourceResult;
try {
sourceResult = getUninterruptibly(inputFuture);
} catch (CancellationException e) {
// Cancel this future and return.
// At this point, inputFuture is cancelled and outputFuture doesn't
// exist, so the value of mayInterruptIfRunning is irrelevant.
cancel(false);
return;
} catch (ExecutionException e) {
// Set the cause of the exception as this future's exception
setException(e.getCause());
return;
}
final ListenableFuture extends O> outputFuture = this.outputFuture = function.apply(sourceResult);
if (isCancelled()) {
outputFuture.cancel(wasInterrupted());
this.outputFuture = null;
return;
}
outputFuture.addListener(new Runnable() {
@Override
public void run() {
try {
set(getUninterruptibly(outputFuture));
} catch (CancellationException e) {
// Cancel this future and return.
// At this point, inputFuture and outputFuture are done, so the
// value of mayInterruptIfRunning is irrelevant.
cancel(false);
return;
} catch (ExecutionException e) {
// Set the cause of the exception as this future's exception
setException(e.getCause());
} finally {
// Don't pin inputs beyond completion
ChainingListenableFuture.this.outputFuture = null;
}
}
}, MoreExecutors.sameThreadExecutor());
} catch (UndeclaredThrowableException e) {
// Set the cause of the exception as this future's exception
setException(e.getCause());
} catch (Throwable t) {
// This exception is irrelevant in this thread, but useful for the
// client
setException(t);
} finally {
// Don't pin inputs beyond completion
function = null;
inputFuture = null;
// Allow our get routines to examine outputFuture now.
outputCreated.countDown();
}
}
}
/**
* Returns a new {@code ListenableFuture} whose result is the product of
* calling {@code get()} on the {@code Future} nested within the given {@code
* Future}, effectively chaining the futures one after the other. Example:
*
* {@code
* SettableFuture> nested = SettableFuture.create();
* ListenableFuture dereferenced = dereference(nested);}
*
* This call has the same cancellation and execution semantics as {@link
* #transform(ListenableFuture, AsyncFunction)}, in that the returned {@code
* Future} attempts to keep its cancellation state in sync with both the
* input {@code Future} and the nested {@code Future}. The transformation
* is very lightweight and therefore takes place in the thread that called
* {@code dereference}.
*
* @param nested The nested future to transform.
* @return A future that holds result of the inner future.
* @since 13.0
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static ListenableFuture dereference(ListenableFuture extends ListenableFuture extends V>> nested) {
return Futures.transform((ListenableFuture) nested, (AsyncFunction) DEREFERENCER);
}
/**
* Helper {@code Function} for {@link #dereference}.
*/
private static final AsyncFunction, Object> DEREFERENCER = new AsyncFunction, Object>() {
@Override
public ListenableFuture