All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.util.concurrent.FluentFuture Maven / Gradle / Ivy

There is a newer version: 30.1
Show newest version
/*
 * 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.checkNotNull;
import static com.google.common.util.concurrent.Internal.toNanosSaturated;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;

import java.time.Duration;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * A {@link ListenableFuture} that supports fluent chains of operations. For example:
 *
 * 
{@code
 * ListenableFuture adminIsLoggedIn =
 *     FluentFuture.from(usersDatabase.getAdminUser())
 *         .transform(User::getId, directExecutor())
 *         .transform(ActivityService::isLoggedIn, threadPool)
 *         .catching(RpcException.class, e -> false, directExecutor());
 * }
* *

Alternatives

* *

Frameworks

* *

When chaining together a graph of asynchronous operations, you will often find it easier to * use a framework. Frameworks automate the process, often adding features like monitoring, * debugging, and cancellation. Examples of frameworks include: * *

* *

{@link java.util.concurrent.CompletableFuture} / {@link java.util.concurrent.CompletionStage} *

* *

Users of {@code CompletableFuture} will likely want to continue using {@code * CompletableFuture}. {@code FluentFuture} is targeted at people who use {@code ListenableFuture}, * who can't use Java 8, or who want an API more focused than {@code CompletableFuture}. (If you * need to adapt between {@code CompletableFuture} and {@code ListenableFuture}, consider Future Converter.) * *

Extension

* * If you want a class like {@code FluentFuture} but with extra methods, we recommend declaring your * own subclass of {@link ListenableFuture}, complete with a method like {@link #from} to adapt an * existing {@code ListenableFuture}, implemented atop a {@link ForwardingListenableFuture} that * forwards to that future and adds the desired methods. * * @since 23.0 */ @Beta @GwtCompatible(emulated = true) public abstract class FluentFuture extends GwtFluentFutureCatchingSpecialization { /** * A less abstract subclass of AbstractFuture. This can be used to optimize setFuture by ensuring * that {@link #get} calls exactly the implementation of {@link AbstractFuture#get}. */ abstract static class TrustedFuture extends FluentFuture implements AbstractFuture.Trusted { @Override public final V get() throws InterruptedException, ExecutionException { return super.get(); } @Override public final V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return super.get(timeout, unit); } @Override public final boolean isDone() { return super.isDone(); } @Override public final boolean isCancelled() { return super.isCancelled(); } @Override public final void addListener(Runnable listener, Executor executor) { super.addListener(listener, executor); } @Override public final boolean cancel(boolean mayInterruptIfRunning) { return super.cancel(mayInterruptIfRunning); } } FluentFuture() {} /** * Converts the given {@code ListenableFuture} to an equivalent {@code FluentFuture}. * *

If the given {@code ListenableFuture} is already a {@code FluentFuture}, it is returned * directly. If not, it is wrapped in a {@code FluentFuture} that delegates all calls to the * original {@code ListenableFuture}. */ public static FluentFuture from(ListenableFuture future) { return future instanceof FluentFuture ? (FluentFuture) future : new ForwardingFluentFuture(future); } /** * Simply returns its argument. * * @deprecated no need to use this * @since 28.0 */ @Deprecated public static FluentFuture from(FluentFuture future) { return checkNotNull(future); } /** * Returns a {@code Future} whose result is taken from this {@code Future} or, if this {@code * Future} fails with the given {@code exceptionType}, from the result provided by the {@code * fallback}. {@link Function#apply} 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}. * *

Usage example: * *

{@code
   * // Falling back to a zero counter in case an exception happens when processing the RPC to fetch
   * // counters.
   * ListenableFuture faultTolerantFuture =
   *     fetchCounters().catching(FetchException.class, x -> 0, directExecutor());
   * }
* *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See * the discussion in the {@link #addListener} documentation. All its warnings about heavyweight * listeners are also applicable to heavyweight functions passed to this method. * *

This method is similar to {@link java.util.concurrent.CompletableFuture#exceptionally}. It * can also serve some of the use cases of {@link java.util.concurrent.CompletableFuture#handle} * and {@link java.util.concurrent.CompletableFuture#handleAsync} when used along with {@link * #transform}. * * @param exceptionType the exception type that triggers use of {@code fallback}. The exception * type is matched against the input's exception. "The input's exception" means the cause of * the {@link ExecutionException} thrown by {@code input.get()} or, if {@code get()} throws a * different kind of exception, that exception itself. To avoid hiding bugs and other * unrecoverable errors, callers should prefer more specific types, avoiding {@code * Throwable.class} in particular. * @param fallback the {@link Function} to be called if the input fails with the expected * exception type. The function's argument is the input's exception. "The input's exception" * means the cause of the {@link ExecutionException} thrown by {@code this.get()} or, if * {@code get()} throws a different kind of exception, that exception itself. * @param executor the executor that runs {@code fallback} if the input fails */ @Partially.GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") public final FluentFuture catching( Class exceptionType, Function fallback, Executor executor) { return (FluentFuture) Futures.catching(this, exceptionType, fallback, executor); } /** * Returns a {@code Future} whose result is taken from this {@code Future} or, if this {@code * Future} fails with the given {@code exceptionType}, from the result provided by the {@code * fallback}. {@link AsyncFunction#apply} 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}. * *

Usage examples: * *

{@code
   * // Falling back to a zero counter in case an exception happens when processing the RPC to fetch
   * // counters.
   * ListenableFuture faultTolerantFuture =
   *     fetchCounters().catchingAsync(
   *         FetchException.class, x -> immediateFuture(0), directExecutor());
   * }
* *

The fallback can also choose to propagate the original exception when desired: * *

{@code
   * // Falling back to a zero counter only in case the exception was a
   * // TimeoutException.
   * ListenableFuture faultTolerantFuture =
   *     fetchCounters().catchingAsync(
   *         FetchException.class,
   *         e -> {
   *           if (omitDataOnFetchFailure) {
   *             return immediateFuture(0);
   *           }
   *           throw e;
   *         },
   *         directExecutor());
   * }
* *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See * the discussion in the {@link #addListener} documentation. All its warnings about heavyweight * listeners are also applicable to heavyweight functions passed to this method. (Specifically, * {@code directExecutor} functions should avoid heavyweight operations inside {@code * AsyncFunction.apply}. Any heavyweight operations should occur in other threads responsible for * completing the returned {@code Future}.) * *

This method is similar to {@link java.util.concurrent.CompletableFuture#exceptionally}. It * can also serve some of the use cases of {@link java.util.concurrent.CompletableFuture#handle} * and {@link java.util.concurrent.CompletableFuture#handleAsync} when used along with {@link * #transform}. * * @param exceptionType the exception type that triggers use of {@code fallback}. The exception * type is matched against the input's exception. "The input's exception" means the cause of * the {@link ExecutionException} thrown by {@code this.get()} or, if {@code get()} throws a * different kind of exception, that exception itself. To avoid hiding bugs and other * unrecoverable errors, callers should prefer more specific types, avoiding {@code * Throwable.class} in particular. * @param fallback the {@link AsyncFunction} to be called if the input fails with the expected * exception type. The function's argument is the input's exception. "The input's exception" * means the cause of the {@link ExecutionException} thrown by {@code input.get()} or, if * {@code get()} throws a different kind of exception, that exception itself. * @param executor the executor that runs {@code fallback} if the input fails */ @Partially.GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") public final FluentFuture catchingAsync( Class exceptionType, AsyncFunction fallback, Executor executor) { return (FluentFuture) Futures.catchingAsync(this, exceptionType, fallback, executor); } /** * Returns a future that delegates to this future but will finish early (via a {@link * TimeoutException} wrapped in an {@link ExecutionException}) if the specified timeout expires. * If the timeout expires, not only will the output future finish, but also the input future * ({@code this}) will be cancelled and interrupted. * * @param timeout when to time out the future * @param scheduledExecutor The executor service to enforce the timeout. * @since 28.0 */ @GwtIncompatible // ScheduledExecutorService public final FluentFuture withTimeout( Duration timeout, ScheduledExecutorService scheduledExecutor) { return withTimeout(toNanosSaturated(timeout), TimeUnit.NANOSECONDS, scheduledExecutor); } /** * Returns a future that delegates to this future but will finish early (via a {@link * TimeoutException} wrapped in an {@link ExecutionException}) if the specified timeout expires. * If the timeout expires, not only will the output future finish, but also the input future * ({@code this}) will be cancelled and interrupted. * * @param timeout when to time out the future * @param unit the time unit of the time parameter * @param scheduledExecutor The executor service to enforce the timeout. */ @GwtIncompatible // ScheduledExecutorService @SuppressWarnings("GoodTime") // should accept a java.time.Duration public final FluentFuture withTimeout( long timeout, TimeUnit unit, ScheduledExecutorService scheduledExecutor) { return (FluentFuture) Futures.withTimeout(this, timeout, unit, scheduledExecutor); } /** * Returns a new {@code Future} whose result is asynchronously derived from the result of this * {@code Future}. If the input {@code Future} fails, the returned {@code Future} fails with the * same exception (and the function is not invoked). * *

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 usage: * *

{@code
   * FluentFuture rowKeyFuture = FluentFuture.from(indexService.lookUp(query));
   * ListenableFuture queryFuture =
   *     rowKeyFuture.transformAsync(dataService::readFuture, executor);
   * }
* *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See * the discussion in the {@link #addListener} documentation. All its warnings about heavyweight * listeners are also applicable to heavyweight functions passed to this method. (Specifically, * {@code directExecutor} functions should avoid heavyweight operations inside {@code * AsyncFunction.apply}. Any heavyweight operations should occur in other threads responsible for * completing the returned {@code Future}.) * *

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. * *

This method is similar to {@link java.util.concurrent.CompletableFuture#thenCompose} and * {@link java.util.concurrent.CompletableFuture#thenComposeAsync}. It can also serve some of the * use cases of {@link java.util.concurrent.CompletableFuture#handle} and {@link * java.util.concurrent.CompletableFuture#handleAsync} when used along with {@link #catching}. * * @param function A function to transform the result of this 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) */ public final FluentFuture transformAsync( AsyncFunction function, Executor executor) { return (FluentFuture) Futures.transformAsync(this, function, executor); } /** * Returns a new {@code Future} whose result is derived from the result of this {@code Future}. If * this input {@code Future} fails, the returned {@code Future} fails with the same exception (and * the function is not invoked). Example usage: * *

{@code
   * ListenableFuture> rowsFuture =
   *     queryFuture.transform(QueryResult::getRows, executor);
   * }
* *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See * the discussion in the {@link #addListener} documentation. All its warnings about heavyweight * listeners are also applicable to heavyweight functions passed to this method. * *

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. * *

This method is similar to {@link java.util.concurrent.CompletableFuture#thenApply} and * {@link java.util.concurrent.CompletableFuture#thenApplyAsync}. It can also serve some of the * use cases of {@link java.util.concurrent.CompletableFuture#handle} and {@link * java.util.concurrent.CompletableFuture#handleAsync} when used along with {@link #catching}. * * @param function A Function to transform the results of this 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. */ public final FluentFuture transform(Function function, Executor executor) { return (FluentFuture) Futures.transform(this, function, executor); } /** * Registers separate success and failure callbacks to be run when this {@code Future}'s * computation is {@linkplain java.util.concurrent.Future#isDone() complete} or, if the * computation is already complete, immediately. * *

The callback is run on {@code executor}. There is no guaranteed ordering of execution of * callbacks, but any callback added through this method is guaranteed to be called once the * computation is complete. * *

Example: * *

{@code
   * future.addCallback(
   *     new FutureCallback() {
   *       public void onSuccess(QueryResult result) {
   *         storeInCache(result);
   *       }
   *       public void onFailure(Throwable t) {
   *         reportError(t);
   *       }
   *     }, executor);
   * }
* *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See * the discussion in the {@link #addListener} documentation. All its warnings about heavyweight * listeners are also applicable to heavyweight callbacks passed to this method. * *

For a more general interface to attach a completion listener, see {@link #addListener}. * *

This method is similar to {@link java.util.concurrent.CompletableFuture#whenComplete} and * {@link java.util.concurrent.CompletableFuture#whenCompleteAsync}. It also serves the use case * of {@link java.util.concurrent.CompletableFuture#thenAccept} and {@link * java.util.concurrent.CompletableFuture#thenAcceptAsync}. * * @param callback The callback to invoke when this {@code Future} is completed. * @param executor The executor to run {@code callback} when the future completes. */ public final void addCallback(FutureCallback callback, Executor executor) { Futures.addCallback(this, callback, executor); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy