Class ClosingFuture<V>
- java.lang.Object
-
- com.google.common.util.concurrent.ClosingFuture<V>
-
- Type Parameters:
V- the type of the value of this step
public final class ClosingFuture<V> extends java.lang.ObjectA step in a pipeline of an asynchronous computation. When the last step in the computation is complete, some objects captured during the computation are closed.A pipeline of
ClosingFutures is a tree of steps. Each step represents either an asynchronously-computed intermediate value, or else an exception that indicates the failure or cancellation of the operation so far. The only way to extract the value or exception from a step is by declaring that step to be the last step of the pipeline. Nevertheless, we refer to the "value" of a successful step or the "result" (value or exception) of any step.- A pipeline starts at its leaf step (or steps), which is created from either a callable
block or a
ListenableFuture. - Each other step is derived from one or more input steps. At each step, zero or more objects can be captured for later closing.
- There is one last step (the root of the tree), from which you can extract the final result of the computation. After that result is available (or the computation fails), all objects captured by any of the steps in the pipeline are closed.
Starting a pipeline
Start aClosingFuturepipeline from a callable block that may capture objects for later closing. To start a pipeline from aListenableFuturethat doesn't create resources that should be closed later, you can usefrom(ListenableFuture)instead.Derived steps
AClosingFuturestep can be derived from one or more inputClosingFuturesteps in ways similar toFluentFutures:- by transforming the value from a successful input step,
- by catching the exception from a failed input step, or
- by combining the results of several input steps.
A step can be the input to at most one derived step. Once you transform its value, catch its exception, or combine it with others, you cannot do anything else with it, including declare it to be the last step of the pipeline.
Transforming
To derive the next step by asynchronously applying a function to an input step's value, calltransform(ClosingFunction, Executor)ortransformAsync(AsyncClosingFunction, Executor)on the input step.Catching
To derive the next step from a failed input step, callcatching(Class, ClosingFunction, Executor)orcatchingAsync(Class, AsyncClosingFunction, Executor)on the input step.Combining
To derive aClosingFuturefrom two or more input steps, pass the input steps towhenAllComplete(Iterable)orwhenAllSucceed(Iterable)or its overloads.Cancelling
Any step in a pipeline can be cancelled, even after another step has been derived, with the same semantics as cancelling aFuture. In addition, a successfully cancelled step will immediately start closing all objects captured for later closing by it and by its input steps.Ending a pipeline
EachClosingFuturepipeline must be ended. To end a pipeline, decide whether you want to close the captured objects automatically or manually.Automatically closing
You can extract aFuturethat represents the result of the last step in the pipeline by callingfinishToFuture(). When that finalFutureis done, all objects captured by all steps in the pipeline will be closed.
In this example, when theFluentFuture<UserName> userName = ClosingFuture.submit( closer -> closer.eventuallyClose(database.newTransaction(), closingExecutor), executor) .transformAsync((closer, transaction) -> transaction.queryClosingFuture("..."), executor) .transform((closer, result) -> result.get("userName"), directExecutor()) .catching(DBException.class, e -> "no user", directExecutor()) .finishToFuture();userNameFutureis done, the transaction and the query result cursor will both be closed, even if the operation is cancelled or fails.Manually closing
If you want to close the captured objects manually, after you've used the final result, callfinishToValueAndCloser(ValueAndCloserConsumer, Executor)to get an object that holds the final result. You then callClosingFuture.ValueAndCloser.closeAsync()to close the captured objects.
In this example, whenClosingFuture.submit( closer -> closer.eventuallyClose(database.newTransaction(), closingExecutor), executor) .transformAsync((closer, transaction) -> transaction.queryClosingFuture("..."), executor) .transform((closer, result) -> result.get("userName"), directExecutor()) .catching(DBException.class, e -> "no user", directExecutor()) .finishToValueAndCloser( valueAndCloser -> this.userNameValueAndCloser = valueAndCloser, executor); // later try { // get() will throw if the operation failed or was cancelled. UserName userName = userNameValueAndCloser.get(); // do something with userName } finally { userNameValueAndCloser.closeAsync(); }userNameValueAndCloser.closeAsync()is called, the transaction and the query result cursor will both be closed, even if the operation is cancelled or fails.Note that if you don't call
closeAsync(), the captured objects will not be closed. The automatic-closing approach described above is safer.- Since:
- 30.0
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static interfaceClosingFuture.AsyncClosingCallable<V>An operation that computes aClosingFutureof a result.static interfaceClosingFuture.AsyncClosingFunction<T,U>A function from an input to aClosingFutureof a result.private static classClosingFuture.CloseableListstatic interfaceClosingFuture.ClosingCallable<V>An operation that computes a result.static interfaceClosingFuture.ClosingFunction<T,U>A function from an input to a result.static classClosingFuture.CombinerA builder of aClosingFuturestep that is derived from more than one input step.static classClosingFuture.Combiner2<V1,V2>A genericClosingFuture.Combinerthat lets you use a lambda or method reference to combine twoClosingFutures.static classClosingFuture.Combiner3<V1,V2,V3>A genericClosingFuture.Combinerthat lets you use a lambda or method reference to combine threeClosingFutures.static classClosingFuture.Combiner4<V1,V2,V3,V4>A genericClosingFuture.Combinerthat lets you use a lambda or method reference to combine fourClosingFutures.static classClosingFuture.Combiner5<V1,V2,V3,V4,V5>A genericClosingFuture.Combinerthat lets you use a lambda or method reference to combine fiveClosingFutures.static classClosingFuture.DeferredCloserAn object that can capture objects to be closed later, when aClosingFuturepipeline is done.static classClosingFuture.PeekerAn object that can return the value of theClosingFutures that are passed towhenAllComplete(Iterable)orwhenAllSucceed(Iterable).(package private) static classClosingFuture.StateThe state of aClosingFuture.CloseableList.static classClosingFuture.ValueAndCloser<V>An object that holds the final result of an asynchronousClosingFutureoperation and allows the user to close all the closeable objects that were captured during it for later closing.static interfaceClosingFuture.ValueAndCloserConsumer<V>Represents an operation that accepts aClosingFuture.ValueAndCloserfor the last step in aClosingFuturepipeline.
-
Field Summary
Fields Modifier and Type Field Description private ClosingFuture.CloseableListcloseablesprivate FluentFuture<V>futureprivate static java.util.logging.Loggerloggerprivate java.util.concurrent.atomic.AtomicReference<ClosingFuture.State>state
-
Constructor Summary
Constructors Modifier Constructor Description privateClosingFuture(ClosingFuture.AsyncClosingCallable<V> callable, java.util.concurrent.Executor executor)privateClosingFuture(ClosingFuture.ClosingCallable<V> callable, java.util.concurrent.Executor executor)privateClosingFuture(ListenableFuture<V> future)
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Deprecated Methods Modifier and Type Method Description private voidbecomeSubsumedInto(ClosingFuture.CloseableList otherCloseables)booleancancel(boolean mayInterruptIfRunning)Attempts to cancel execution of this step.<X extends java.lang.Throwable>
ClosingFuture<V>catching(java.lang.Class<X> exceptionType, ClosingFuture.ClosingFunction<? super X,? extends V> fallback, java.util.concurrent.Executor executor)Returns a newClosingFuturepipeline step derived from this one by applying a function to its exception if it is an instance of a given exception type.<X extends java.lang.Throwable>
ClosingFuture<V>catchingAsync(java.lang.Class<X> exceptionType, ClosingFuture.AsyncClosingFunction<? super X,? extends V> fallback, java.util.concurrent.Executor executor)Returns a newClosingFuturepipeline step derived from this one by applying a function that returns aClosingFutureto its exception if it is an instance of a given exception type.private <X extends java.lang.Throwable,W extends V>
ClosingFuture<V>catchingAsyncMoreGeneric(java.lang.Class<X> exceptionType, ClosingFuture.AsyncClosingFunction<? super X,W> fallback, java.util.concurrent.Executor executor)private <X extends java.lang.Throwable,W extends V>
ClosingFuture<V>catchingMoreGeneric(java.lang.Class<X> exceptionType, ClosingFuture.ClosingFunction<? super X,W> fallback, java.util.concurrent.Executor executor)private voidcheckAndUpdateState(ClosingFuture.State oldState, ClosingFuture.State newState)private voidclose()private static voidcloseQuietly(java.lang.AutoCloseable closeable, java.util.concurrent.Executor executor)private booleancompareAndUpdateState(ClosingFuture.State oldState, ClosingFuture.State newState)private <U> ClosingFuture<U>derive(FluentFuture<U> future)static <C extends java.lang.Object & java.lang.AutoCloseable>
ClosingFuture<C>eventuallyClosing(ListenableFuture<C> future, java.util.concurrent.Executor closingExecutor)Deprecated.CreatingFutures of closeable types is dangerous in general because the underlying value may never be closed if theFutureis canceled after its operation begins.protected voidfinalize()FluentFuture<V>finishToFuture()Marks this step as the last step in theClosingFuturepipeline.voidfinishToValueAndCloser(ClosingFuture.ValueAndCloserConsumer<? super V> consumer, java.util.concurrent.Executor executor)Marks this step as the last step in theClosingFuturepipeline.static <V> ClosingFuture<V>from(ListenableFuture<V> future)Starts aClosingFuturepipeline with aListenableFuture.private static <C,V extends C>
voidprovideValueAndCloser(ClosingFuture.ValueAndCloserConsumer<C> consumer, ClosingFuture<V> closingFuture)ListenableFuture<?>statusFuture()Returns a future that finishes when this step does.static <V> ClosingFuture<V>submit(ClosingFuture.ClosingCallable<V> callable, java.util.concurrent.Executor executor)Starts aClosingFuturepipeline by submitting a callable block to an executor.static <V> ClosingFuture<V>submitAsync(ClosingFuture.AsyncClosingCallable<V> callable, java.util.concurrent.Executor executor)Starts aClosingFuturepipeline by submitting a callable block to an executor.java.lang.StringtoString()<U> ClosingFuture<U>transform(ClosingFuture.ClosingFunction<? super V,U> function, java.util.concurrent.Executor executor)Returns a newClosingFuturepipeline step derived from this one by applying a function to its value.<U> ClosingFuture<U>transformAsync(ClosingFuture.AsyncClosingFunction<? super V,U> function, java.util.concurrent.Executor executor)Returns a newClosingFuturepipeline step derived from this one by applying a function that returns aClosingFutureto its value.static ClosingFuture.CombinerwhenAllComplete(ClosingFuture<?> future1, ClosingFuture<?>... moreFutures)Starts specifying how to combineClosingFutures into a single pipeline.static ClosingFuture.CombinerwhenAllComplete(java.lang.Iterable<? extends ClosingFuture<?>> futures)Starts specifying how to combineClosingFutures into a single pipeline.static ClosingFuture.CombinerwhenAllSucceed(ClosingFuture<?> future1, ClosingFuture<?> future2, ClosingFuture<?> future3, ClosingFuture<?> future4, ClosingFuture<?> future5, ClosingFuture<?> future6, ClosingFuture<?>... moreFutures)Starts specifying how to combineClosingFutures into a single pipeline, assuming they all succeed.static <V1,V2>
ClosingFuture.Combiner2<V1,V2>whenAllSucceed(ClosingFuture<V1> future1, ClosingFuture<V2> future2)Starts specifying how to combine twoClosingFutures into a single pipeline, assuming they all succeed.static <V1,V2,V3>
ClosingFuture.Combiner3<V1,V2,V3>whenAllSucceed(ClosingFuture<V1> future1, ClosingFuture<V2> future2, ClosingFuture<V3> future3)Starts specifying how to combine threeClosingFutures into a single pipeline, assuming they all succeed.static <V1,V2,V3,V4>
ClosingFuture.Combiner4<V1,V2,V3,V4>whenAllSucceed(ClosingFuture<V1> future1, ClosingFuture<V2> future2, ClosingFuture<V3> future3, ClosingFuture<V4> future4)Starts specifying how to combine fourClosingFutures into a single pipeline, assuming they all succeed.static <V1,V2,V3,V4,V5>
ClosingFuture.Combiner5<V1,V2,V3,V4,V5>whenAllSucceed(ClosingFuture<V1> future1, ClosingFuture<V2> future2, ClosingFuture<V3> future3, ClosingFuture<V4> future4, ClosingFuture<V5> future5)Starts specifying how to combine fiveClosingFutures into a single pipeline, assuming they all succeed.static ClosingFuture.CombinerwhenAllSucceed(java.lang.Iterable<? extends ClosingFuture<?>> futures)Starts specifying how to combineClosingFutures into a single pipeline, assuming they all succeed.(package private) java.util.concurrent.CountDownLatchwhenClosedCountDown()Returns an object that can be used to wait until this objects' deferred closeables have all hadRunnables that close them submitted to each one's closingExecutor.static <V,U>
ClosingFuture.AsyncClosingFunction<V,U>withoutCloser(AsyncFunction<V,U> function)Returns anClosingFuture.AsyncClosingFunctionthat applies anAsyncFunctionto an input, ignoring the DeferredCloser and returning aClosingFuturederived from the returnedListenableFuture.
-
-
-
Field Detail
-
logger
private static final java.util.logging.Logger logger
-
state
private final java.util.concurrent.atomic.AtomicReference<ClosingFuture.State> state
-
closeables
private final ClosingFuture.CloseableList closeables
-
future
private final FluentFuture<V> future
-
-
Constructor Detail
-
ClosingFuture
private ClosingFuture(ListenableFuture<V> future)
-
ClosingFuture
private ClosingFuture(ClosingFuture.ClosingCallable<V> callable, java.util.concurrent.Executor executor)
-
ClosingFuture
private ClosingFuture(ClosingFuture.AsyncClosingCallable<V> callable, java.util.concurrent.Executor executor)
-
-
Method Detail
-
submit
public static <V> ClosingFuture<V> submit(ClosingFuture.ClosingCallable<V> callable, java.util.concurrent.Executor executor)
Starts aClosingFuturepipeline by submitting a callable block to an executor.- Throws:
java.util.concurrent.RejectedExecutionException- if the task cannot be scheduled for execution
-
submitAsync
public static <V> ClosingFuture<V> submitAsync(ClosingFuture.AsyncClosingCallable<V> callable, java.util.concurrent.Executor executor)
Starts aClosingFuturepipeline by submitting a callable block to an executor.- Throws:
java.util.concurrent.RejectedExecutionException- if the task cannot be scheduled for execution- Since:
- 30.1
-
from
public static <V> ClosingFuture<V> from(ListenableFuture<V> future)
Starts aClosingFuturepipeline with aListenableFuture.future's value will not be closed when the pipeline is done even ifVimplementsCloseable. In order to start a pipeline with a value that will be closed when the pipeline is done, usesubmit(ClosingCallable, Executor)instead.
-
eventuallyClosing
@Deprecated public static <C extends java.lang.Object & java.lang.AutoCloseable> ClosingFuture<C> eventuallyClosing(ListenableFuture<C> future, java.util.concurrent.Executor closingExecutor)
Deprecated.CreatingFutures of closeable types is dangerous in general because the underlying value may never be closed if theFutureis canceled after its operation begins. Consider replacing code that createsListenableFutures of closeable types, including those that pass them to this method, withsubmit(ClosingCallable, Executor)in order to ensure that resources do not leak. Or, to start a pipeline with aListenableFuturethat doesn't create values that should be closed, usefrom(com.google.common.util.concurrent.ListenableFuture<V>).Starts aClosingFuturepipeline with aListenableFuture.If
futuresucceeds, its value will be closed (usingclosingExecutor)when the pipeline is done, even if the pipeline is canceled or fails.Cancelling the pipeline will not cancel
future, so that the pipeline can access its value in order to close it.- Parameters:
future- the future to create theClosingFuturefrom. For discussion of the future's result typeC, seeDeferredCloser#eventuallyClose(Closeable, Executor).closingExecutor- the future's result will be closed on this executor
-
whenAllComplete
public static ClosingFuture.Combiner whenAllComplete(java.lang.Iterable<? extends ClosingFuture<?>> futures)
Starts specifying how to combineClosingFutures into a single pipeline.- Throws:
java.lang.IllegalStateException- if aClosingFuturehas already been derived from any of thefutures, or if any has already been finished
-
whenAllComplete
public static ClosingFuture.Combiner whenAllComplete(ClosingFuture<?> future1, ClosingFuture<?>... moreFutures)
Starts specifying how to combineClosingFutures into a single pipeline.- Throws:
java.lang.IllegalStateException- if aClosingFuturehas already been derived from any of the arguments, or if any has already been finished
-
whenAllSucceed
public static ClosingFuture.Combiner whenAllSucceed(java.lang.Iterable<? extends ClosingFuture<?>> futures)
Starts specifying how to combineClosingFutures into a single pipeline, assuming they all succeed. If any fail, the resulting pipeline will fail.- Throws:
java.lang.IllegalStateException- if aClosingFuturehas already been derived from any of thefutures, or if any has already been finished
-
whenAllSucceed
public static <V1,V2> ClosingFuture.Combiner2<V1,V2> whenAllSucceed(ClosingFuture<V1> future1, ClosingFuture<V2> future2)
Starts specifying how to combine twoClosingFutures into a single pipeline, assuming they all succeed. If any fail, the resulting pipeline will fail.Calling this method allows you to use lambdas or method references typed with the types of the input
ClosingFutures.- Throws:
java.lang.IllegalStateException- if aClosingFuturehas already been derived from any of the arguments, or if any has already been finished
-
whenAllSucceed
public static <V1,V2,V3> ClosingFuture.Combiner3<V1,V2,V3> whenAllSucceed(ClosingFuture<V1> future1, ClosingFuture<V2> future2, ClosingFuture<V3> future3)
Starts specifying how to combine threeClosingFutures into a single pipeline, assuming they all succeed. If any fail, the resulting pipeline will fail.Calling this method allows you to use lambdas or method references typed with the types of the input
ClosingFutures.- Throws:
java.lang.IllegalStateException- if aClosingFuturehas already been derived from any of the arguments, or if any has already been finished
-
whenAllSucceed
public static <V1,V2,V3,V4> ClosingFuture.Combiner4<V1,V2,V3,V4> whenAllSucceed(ClosingFuture<V1> future1, ClosingFuture<V2> future2, ClosingFuture<V3> future3, ClosingFuture<V4> future4)
Starts specifying how to combine fourClosingFutures into a single pipeline, assuming they all succeed. If any fail, the resulting pipeline will fail.Calling this method allows you to use lambdas or method references typed with the types of the input
ClosingFutures.- Throws:
java.lang.IllegalStateException- if aClosingFuturehas already been derived from any of the arguments, or if any has already been finished
-
whenAllSucceed
public static <V1,V2,V3,V4,V5> ClosingFuture.Combiner5<V1,V2,V3,V4,V5> whenAllSucceed(ClosingFuture<V1> future1, ClosingFuture<V2> future2, ClosingFuture<V3> future3, ClosingFuture<V4> future4, ClosingFuture<V5> future5)
Starts specifying how to combine fiveClosingFutures into a single pipeline, assuming they all succeed. If any fail, the resulting pipeline will fail.Calling this method allows you to use lambdas or method references typed with the types of the input
ClosingFutures.- Throws:
java.lang.IllegalStateException- if aClosingFuturehas already been derived from any of the arguments, or if any has already been finished
-
whenAllSucceed
public static ClosingFuture.Combiner whenAllSucceed(ClosingFuture<?> future1, ClosingFuture<?> future2, ClosingFuture<?> future3, ClosingFuture<?> future4, ClosingFuture<?> future5, ClosingFuture<?> future6, ClosingFuture<?>... moreFutures)
Starts specifying how to combineClosingFutures into a single pipeline, assuming they all succeed. If any fail, the resulting pipeline will fail.- Throws:
java.lang.IllegalStateException- if aClosingFuturehas already been derived from any of the arguments, or if any has already been finished
-
statusFuture
public ListenableFuture<?> statusFuture()
Returns a future that finishes when this step does. Callingget()on the returned future returnsnullif the step is successful or throws the same exception that would be thrown by callingfinishToFuture().get()if this were the last step. Callingcancel()on the returned future has no effect on theClosingFuturepipeline.statusFuturediffers from most methods onClosingFuture: You can make calls tostatusFuturein addition to the call you make tofinishToFuture()or a derivation method on the same instance. This is important because callingstatusFuturealone does not provide a way to close the pipeline.
-
transform
public <U> ClosingFuture<U> transform(ClosingFuture.ClosingFunction<? super V,U> function, java.util.concurrent.Executor executor)
Returns a newClosingFuturepipeline step derived from this one by applying a function to its value. The function can use aClosingFuture.DeferredCloserto capture objects to be closed when the pipeline is done.If this
ClosingFuturefails, the function will not be called, and the derivedClosingFuturewill be equivalent to this one.If the function throws an exception, that exception is used as the result of the derived
ClosingFuture.Example usage:
ClosingFuture<List<Row>> rowsFuture = queryFuture.transform((closer, result) -> result.getRows(), executor);When selecting an executor, note that
directExecutoris dangerous in some cases. See the discussion in theListenableFuture.addListener(java.lang.Runnable, java.util.concurrent.Executor)documentation. All its warnings about heavyweight listeners are also applicable to heavyweight functions passed to this method.After calling this method, you may not call
finishToFuture(),finishToValueAndCloser(ValueAndCloserConsumer, Executor), or any other derivation method on thisClosingFuture.- Parameters:
function- transforms the value of this step to the value of the derived stepexecutor- executor to run the function in- Returns:
- the derived step
- Throws:
java.lang.IllegalStateException- if aClosingFuturehas already been derived from this one, or if thisClosingFuturehas already been finished
-
transformAsync
public <U> ClosingFuture<U> transformAsync(ClosingFuture.AsyncClosingFunction<? super V,U> function, java.util.concurrent.Executor executor)
Returns a newClosingFuturepipeline step derived from this one by applying a function that returns aClosingFutureto its value. The function can use aClosingFuture.DeferredCloserto capture objects to be closed when the pipeline is done (other than those captured by the returnedClosingFuture).If this
ClosingFuturesucceeds, the derived one will be equivalent to the one returned by the function.If this
ClosingFuturefails, the function will not be called, and the derivedClosingFuturewill be equivalent to this one.If the function throws an exception, that exception is used as the result of the derived
ClosingFuture. But if the exception is thrown after the function creates aClosingFuture, then none of the closeable objects in thatClosingFuturewill be closed.Usage guidelines for this method:
- Use this method only when calling an API that returns a
ListenableFutureor aClosingFuture. If possible, prefer callingtransform(ClosingFunction, Executor)instead, with a function that returns the next value directly. - Call
closer.eventuallyClose()for every closeable object this step creates in order to capture it for later closing. - Return a
ClosingFuture. To turn aListenableFutureinto aClosingFuturecallfrom(ListenableFuture). - In case this step doesn't create new closeables, you can adapt an API that returns a
ListenableFutureto return aClosingFutureby wrapping it with a call towithoutCloser(AsyncFunction)
Example usage:
// Result.getRowsClosingFuture() returns a ClosingFuture. ClosingFuture<List<Row>> rowsFuture = queryFuture.transformAsync((closer, result) -> result.getRowsClosingFuture(), executor); // Result.writeRowsToOutputStreamFuture() returns a ListenableFuture that resolves to the // number of written rows. openOutputFile() returns a FileOutputStream (which implements // Closeable). ClosingFuture<Integer> rowsFuture2 = queryFuture.transformAsync( (closer, result) -> { FileOutputStream fos = closer.eventuallyClose(openOutputFile(), closingExecutor); return ClosingFuture.from(result.writeRowsToOutputStreamFuture(fos)); }, executor); // Result.getRowsFuture() returns a ListenableFuture (no new closeables are created). ClosingFuture<List<Row>> rowsFuture3 = queryFuture.transformAsync(withoutCloser(Result::getRowsFuture), executor);When selecting an executor, note that
directExecutoris dangerous in some cases. See the discussion in theListenableFuture.addListener(java.lang.Runnable, java.util.concurrent.Executor)documentation. All its warnings about heavyweight listeners are also applicable to heavyweight functions passed to this method. (Specifically,directExecutorfunctions should avoid heavyweight operations insideAsyncClosingFunction.apply. Any heavyweight operations should occur in other threads responsible for completing the returnedClosingFuture.)After calling this method, you may not call
finishToFuture(),finishToValueAndCloser(ValueAndCloserConsumer, Executor), or any other derivation method on thisClosingFuture.- Parameters:
function- transforms the value of this step to aClosingFuturewith the value of the derived stepexecutor- executor to run the function in- Returns:
- the derived step
- Throws:
java.lang.IllegalStateException- if aClosingFuturehas already been derived from this one, or if thisClosingFuturehas already been finished
- Use this method only when calling an API that returns a
-
withoutCloser
public static <V,U> ClosingFuture.AsyncClosingFunction<V,U> withoutCloser(AsyncFunction<V,U> function)
Returns anClosingFuture.AsyncClosingFunctionthat applies anAsyncFunctionto an input, ignoring the DeferredCloser and returning aClosingFuturederived from the returnedListenableFuture.Use this method to pass a transformation to
transformAsync(AsyncClosingFunction, Executor)or tocatchingAsync(Class, AsyncClosingFunction, Executor)as long as it meets these conditions:- It does not need to capture any
Closeableobjects by callingDeferredCloser#eventuallyClose(Closeable, Executor). - It returns a
ListenableFuture.
Example usage:
// Result.getRowsFuture() returns a ListenableFuture. ClosingFuture<List<Row>> rowsFuture = queryFuture.transformAsync(withoutCloser(Result::getRowsFuture), executor);- Parameters:
function- transforms the value of aClosingFuturestep to aListenableFuturewith the value of a derived step
- It does not need to capture any
-
catching
public <X extends java.lang.Throwable> ClosingFuture<V> catching(java.lang.Class<X> exceptionType, ClosingFuture.ClosingFunction<? super X,? extends V> fallback, java.util.concurrent.Executor executor)
Returns a newClosingFuturepipeline step derived from this one by applying a function to its exception if it is an instance of a given exception type. The function can use aClosingFuture.DeferredCloserto capture objects to be closed when the pipeline is done.If this
ClosingFuturesucceeds or fails with a different exception type, the function will not be called, and the derivedClosingFuturewill be equivalent to this one.If the function throws an exception, that exception is used as the result of the derived
ClosingFuture.Example usage:
ClosingFuture<QueryResult> queryFuture = queryFuture.catching( QueryException.class, (closer, x) -> Query.emptyQueryResult(), executor);When selecting an executor, note that
directExecutoris dangerous in some cases. See the discussion in theListenableFuture.addListener(java.lang.Runnable, java.util.concurrent.Executor)documentation. All its warnings about heavyweight listeners are also applicable to heavyweight functions passed to this method.After calling this method, you may not call
finishToFuture(),finishToValueAndCloser(ValueAndCloserConsumer, Executor), or any other derivation method on thisClosingFuture.- Parameters:
exceptionType- the exception type that triggers use offallback. The exception type is matched against this step's exception. "This step's exception" means the cause of theExecutionExceptionthrown byFuture.get()on theFutureunderlying this step or, ifget()throws a different kind of exception, that exception itself. To avoid hiding bugs and other unrecoverable errors, callers should prefer more specific types, avoidingThrowable.classin particular.fallback- the function to be called if this step fails with the expected exception type. The function's argument is this step's exception. "This step's exception" means the cause of theExecutionExceptionthrown byFuture.get()on theFutureunderlying this step or, ifget()throws a different kind of exception, that exception itself.executor- the executor that runsfallbackif the input fails
-
catchingMoreGeneric
private <X extends java.lang.Throwable,W extends V> ClosingFuture<V> catchingMoreGeneric(java.lang.Class<X> exceptionType, ClosingFuture.ClosingFunction<? super X,W> fallback, java.util.concurrent.Executor executor)
-
catchingAsync
public <X extends java.lang.Throwable> ClosingFuture<V> catchingAsync(java.lang.Class<X> exceptionType, ClosingFuture.AsyncClosingFunction<? super X,? extends V> fallback, java.util.concurrent.Executor executor)
Returns a newClosingFuturepipeline step derived from this one by applying a function that returns aClosingFutureto its exception if it is an instance of a given exception type. The function can use aClosingFuture.DeferredCloserto capture objects to be closed when the pipeline is done (other than those captured by the returnedClosingFuture).If this
ClosingFuturefails with an exception of the given type, the derivedClosingFuturewill be equivalent to the one returned by the function.If this
ClosingFuturesucceeds or fails with a different exception type, the function will not be called, and the derivedClosingFuturewill be equivalent to this one.If the function throws an exception, that exception is used as the result of the derived
ClosingFuture. But if the exception is thrown after the function creates aClosingFuture, then none of the closeable objects in thatClosingFuturewill be closed.Usage guidelines for this method:
- Use this method only when calling an API that returns a
ListenableFutureor aClosingFuture. If possible, prefer callingcatching(Class, ClosingFunction, Executor)instead, with a function that returns the next value directly. - Call
closer.eventuallyClose()for every closeable object this step creates in order to capture it for later closing. - Return a
ClosingFuture. To turn aListenableFutureinto aClosingFuturecallfrom(ListenableFuture). - In case this step doesn't create new closeables, you can adapt an API that returns a
ListenableFutureto return aClosingFutureby wrapping it with a call towithoutCloser(AsyncFunction)
Example usage:
// Fall back to a secondary input stream in case of IOException. ClosingFuture<InputStream> inputFuture = firstInputFuture.catchingAsync( IOException.class, (closer, x) -> secondaryInputStreamClosingFuture(), executor);}When selecting an executor, note that
directExecutoris dangerous in some cases. See the discussion in theListenableFuture.addListener(java.lang.Runnable, java.util.concurrent.Executor)documentation. All its warnings about heavyweight listeners are also applicable to heavyweight functions passed to this method. (Specifically,directExecutorfunctions should avoid heavyweight operations insideAsyncClosingFunction.apply. Any heavyweight operations should occur in other threads responsible for completing the returnedClosingFuture.)After calling this method, you may not call
finishToFuture(),finishToValueAndCloser(ValueAndCloserConsumer, Executor), or any other derivation method on thisClosingFuture.- Parameters:
exceptionType- the exception type that triggers use offallback. The exception type is matched against this step's exception. "This step's exception" means the cause of theExecutionExceptionthrown byFuture.get()on theFutureunderlying this step or, ifget()throws a different kind of exception, that exception itself. To avoid hiding bugs and other unrecoverable errors, callers should prefer more specific types, avoidingThrowable.classin particular.fallback- the function to be called if this step fails with the expected exception type. The function's argument is this step's exception. "This step's exception" means the cause of theExecutionExceptionthrown byFuture.get()on theFutureunderlying this step or, ifget()throws a different kind of exception, that exception itself.executor- the executor that runsfallbackif the input fails
- Use this method only when calling an API that returns a
-
catchingAsyncMoreGeneric
private <X extends java.lang.Throwable,W extends V> ClosingFuture<V> catchingAsyncMoreGeneric(java.lang.Class<X> exceptionType, ClosingFuture.AsyncClosingFunction<? super X,W> fallback, java.util.concurrent.Executor executor)
-
finishToFuture
public FluentFuture<V> finishToFuture()
Marks this step as the last step in theClosingFuturepipeline. When the returnedFutureis done, all objects captured for closing during the pipeline's computation will be closed.After calling this method, you may not call
finishToValueAndCloser(ValueAndCloserConsumer, Executor), this method, or any other derivation method on thisClosingFuture.- Returns:
- a
Futurethat represents the final value or exception of the pipeline
-
finishToValueAndCloser
public void finishToValueAndCloser(ClosingFuture.ValueAndCloserConsumer<? super V> consumer, java.util.concurrent.Executor executor)
Marks this step as the last step in theClosingFuturepipeline. When this step is done,receiverwill be called with an object that contains the result of the operation. The receiver can store theClosingFuture.ValueAndCloseroutside the receiver for later synchronous use.After calling this method, you may not call
finishToFuture(), this method again, or any other derivation method on thisClosingFuture.- Parameters:
consumer- a callback whose method will be called (usingexecutor) when this operation is done
-
provideValueAndCloser
private static <C,V extends C> void provideValueAndCloser(ClosingFuture.ValueAndCloserConsumer<C> consumer, ClosingFuture<V> closingFuture)
-
cancel
public boolean cancel(boolean mayInterruptIfRunning)
Attempts to cancel execution of this step. This attempt will fail if the step has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this step has not started whencancelis called, this step should never run.If successful, causes the objects captured by this step (if already started) and its input step(s) for later closing to be closed on their respective
Executors. If any such calls specifiedMoreExecutors.directExecutor(), those objects will be closed synchronously.- Parameters:
mayInterruptIfRunning-trueif the thread executing this task should be interrupted; otherwise, in-progress tasks are allowed to complete, but the step will be cancelled regardless- Returns:
falseif the step could not be cancelled, typically because it has already completed normally;trueotherwise
-
close
private void close()
-
derive
private <U> ClosingFuture<U> derive(FluentFuture<U> future)
-
becomeSubsumedInto
private void becomeSubsumedInto(ClosingFuture.CloseableList otherCloseables)
-
toString
public java.lang.String toString()
- Overrides:
toStringin classjava.lang.Object
-
finalize
protected void finalize()
- Overrides:
finalizein classjava.lang.Object
-
closeQuietly
private static void closeQuietly(java.lang.AutoCloseable closeable, java.util.concurrent.Executor executor)
-
checkAndUpdateState
private void checkAndUpdateState(ClosingFuture.State oldState, ClosingFuture.State newState)
-
compareAndUpdateState
private boolean compareAndUpdateState(ClosingFuture.State oldState, ClosingFuture.State newState)
-
whenClosedCountDown
java.util.concurrent.CountDownLatch whenClosedCountDown()
Returns an object that can be used to wait until this objects' deferred closeables have all hadRunnables that close them submitted to each one's closingExecutor.
-
-