Coverage Summary for Class: AbstractTransformFuture (com.google.common.util.concurrent)

Class Method, % Line, %
AbstractTransformFuture 0% (0/6) 0% (0/48)
AbstractTransformFuture$AsyncTransformFuture 0% (0/3) 0% (0/5)
AbstractTransformFuture$TransformFuture 0% (0/3) 0% (0/3)
Total 0% (0/12) 0% (0/56)


1 /* 2  * Copyright (C) 2006 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5  * in compliance with the License. You may obtain a copy of the License at 6  * 7  * http://www.apache.org/licenses/LICENSE-2.0 8  * 9  * Unless required by applicable law or agreed to in writing, software distributed under the License 10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11  * or implied. See the License for the specific language governing permissions and limitations under 12  * the License. 13  */ 14  15 package com.google.common.util.concurrent; 16  17 import static com.google.common.base.Preconditions.checkNotNull; 18 import static com.google.common.util.concurrent.Futures.getDone; 19 import static com.google.common.util.concurrent.MoreExecutors.rejectionPropagatingExecutor; 20  21 import com.google.common.annotations.GwtCompatible; 22 import com.google.common.base.Function; 23 import com.google.errorprone.annotations.ForOverride; 24 import java.util.concurrent.CancellationException; 25 import java.util.concurrent.ExecutionException; 26 import java.util.concurrent.Executor; 27 import javax.annotation.CheckForNull; 28 import org.checkerframework.checker.nullness.qual.Nullable; 29  30 /** Implementations of {@code Futures.transform*}. */ 31 @GwtCompatible 32 @ElementTypesAreNonnullByDefault 33 abstract class AbstractTransformFuture< 34  I extends @Nullable Object, O extends @Nullable Object, F, T extends @Nullable Object> 35  extends FluentFuture.TrustedFuture<O> implements Runnable { 36  static <I extends @Nullable Object, O extends @Nullable Object> ListenableFuture<O> create( 37  ListenableFuture<I> input, 38  AsyncFunction<? super I, ? extends O> function, 39  Executor executor) { 40  checkNotNull(executor); 41  AsyncTransformFuture<I, O> output = new AsyncTransformFuture<>(input, function); 42  input.addListener(output, rejectionPropagatingExecutor(executor, output)); 43  return output; 44  } 45  46  static <I extends @Nullable Object, O extends @Nullable Object> ListenableFuture<O> create( 47  ListenableFuture<I> input, Function<? super I, ? extends O> function, Executor executor) { 48  checkNotNull(function); 49  TransformFuture<I, O> output = new TransformFuture<>(input, function); 50  input.addListener(output, rejectionPropagatingExecutor(executor, output)); 51  return output; 52  } 53  54  /* 55  * In certain circumstances, this field might theoretically not be visible to an afterDone() call 56  * triggered by cancel(). For details, see the comments on the fields of TimeoutFuture. 57  */ 58  @CheckForNull ListenableFuture<? extends I> inputFuture; 59  @CheckForNull F function; 60  61  AbstractTransformFuture(ListenableFuture<? extends I> inputFuture, F function) { 62  this.inputFuture = checkNotNull(inputFuture); 63  this.function = checkNotNull(function); 64  } 65  66  @Override 67  public final void run() { 68  ListenableFuture<? extends I> localInputFuture = inputFuture; 69  F localFunction = function; 70  if (isCancelled() | localInputFuture == null | localFunction == null) { 71  return; 72  } 73  inputFuture = null; 74  75  if (localInputFuture.isCancelled()) { 76  @SuppressWarnings("unchecked") 77  boolean unused = 78  setFuture((ListenableFuture<O>) localInputFuture); // Respects cancellation cause setting 79  return; 80  } 81  82  /* 83  * Any of the setException() calls below can fail if the output Future is cancelled between now 84  * and then. This means that we're silently swallowing an exception -- maybe even an Error. But 85  * this is no worse than what FutureTask does in that situation. Additionally, because the 86  * Future was cancelled, its listeners have been run, so its consumers will not hang. 87  * 88  * Contrast this to the situation we have if setResult() throws, a situation described below. 89  */ 90  I sourceResult; 91  try { 92  sourceResult = getDone(localInputFuture); 93  } catch (CancellationException e) { 94  // TODO(user): verify future behavior - unify logic with getFutureValue in AbstractFuture. This 95  // code should be unreachable with correctly implemented Futures. 96  // Cancel this future and return. 97  // At this point, inputFuture is cancelled and outputFuture doesn't exist, so the value of 98  // mayInterruptIfRunning is irrelevant. 99  cancel(false); 100  return; 101  } catch (ExecutionException e) { 102  // Set the cause of the exception as this future's exception. 103  setException(e.getCause()); 104  return; 105  } catch (RuntimeException e) { 106  // Bug in inputFuture.get(). Propagate to the output Future so that its consumers don't hang. 107  setException(e); 108  return; 109  } catch (Error e) { 110  /* 111  * StackOverflowError, OutOfMemoryError (e.g., from allocating ExecutionException), or 112  * something. Try to treat it like a RuntimeException. If we overflow the stack again, the 113  * resulting Error will propagate upward up to the root call to set(). 114  */ 115  setException(e); 116  return; 117  } 118  119  T transformResult; 120  try { 121  transformResult = doTransform(localFunction, sourceResult); 122  } catch (Throwable t) { 123  // This exception is irrelevant in this thread, but useful for the client. 124  setException(t); 125  return; 126  } finally { 127  function = null; 128  } 129  130  /* 131  * If set()/setValue() throws an Error, we let it propagate. Why? The most likely Error is a 132  * StackOverflowError (from deep transform(..., directExecutor()) nesting), and calling 133  * setException(stackOverflowError) would fail: 134  * 135  * - If the stack overflowed before set()/setValue() could even store the result in the output 136  * Future, then a call setException() would likely also overflow. 137  * 138  * - If the stack overflowed after set()/setValue() stored its result, then a call to 139  * setException() will be a no-op because the Future is already done. 140  * 141  * Both scenarios are bad: The output Future might never complete, or, if it does complete, it 142  * might not run some of its listeners. The likely result is that the app will hang. (And of 143  * course stack overflows are bad news in general. For example, we may have overflowed in the 144  * middle of defining a class. If so, that class will never be loadable in this process.) The 145  * best we can do (since logging may overflow the stack) is to let the error propagate. Because 146  * it is an Error, it won't be caught and logged by AbstractFuture.executeListener. Instead, it 147  * can propagate through many layers of AbstractTransformFuture up to the root call to set(). 148  * 149  * https://github.com/google/guava/issues/2254 150  * 151  * Other kinds of Errors are possible: 152  * 153  * - OutOfMemoryError from allocations in setFuture(): The calculus here is similar to 154  * StackOverflowError: We can't reliably call setException(error). 155  * 156  * - Any kind of Error from a listener. Even if we could distinguish that case (by exposing some 157  * extra state from AbstractFuture), our options are limited: A call to setException() would be 158  * a no-op. We could log, but if that's what we really want, we should modify 159  * AbstractFuture.executeListener to do so, since that method would have the ability to continue 160  * to execute other listeners. 161  * 162  * What about RuntimeException? If there is a bug in set()/setValue() that produces one, it will 163  * propagate, too, but only as far as AbstractFuture.executeListener, which will catch and log 164  * it. 165  */ 166  setResult(transformResult); 167  } 168  169  /** Template method for subtypes to actually run the transform. */ 170  @ForOverride 171  @ParametricNullness 172  abstract T doTransform(F function, @ParametricNullness I result) throws Exception; 173  174  /** Template method for subtypes to actually set the result. */ 175  @ForOverride 176  abstract void setResult(@ParametricNullness T result); 177  178  @Override 179  protected final void afterDone() { 180  maybePropagateCancellationTo(inputFuture); 181  this.inputFuture = null; 182  this.function = null; 183  } 184  185  @Override 186  @CheckForNull 187  protected String pendingToString() { 188  ListenableFuture<? extends I> localInputFuture = inputFuture; 189  F localFunction = function; 190  String superString = super.pendingToString(); 191  String resultString = ""; 192  if (localInputFuture != null) { 193  resultString = "inputFuture=[" + localInputFuture + "], "; 194  } 195  if (localFunction != null) { 196  return resultString + "function=[" + localFunction + "]"; 197  } else if (superString != null) { 198  return resultString + superString; 199  } 200  return null; 201  } 202  203  /** 204  * An {@link AbstractTransformFuture} that delegates to an {@link AsyncFunction} and {@link 205  * #setFuture(ListenableFuture)}. 206  */ 207  private static final class AsyncTransformFuture< 208  I extends @Nullable Object, O extends @Nullable Object> 209  extends AbstractTransformFuture< 210  I, O, AsyncFunction<? super I, ? extends O>, ListenableFuture<? extends O>> { 211  AsyncTransformFuture( 212  ListenableFuture<? extends I> inputFuture, AsyncFunction<? super I, ? extends O> function) { 213  super(inputFuture, function); 214  } 215  216  @Override 217  ListenableFuture<? extends O> doTransform( 218  AsyncFunction<? super I, ? extends O> function, @ParametricNullness I input) 219  throws Exception { 220  ListenableFuture<? extends O> outputFuture = function.apply(input); 221  checkNotNull( 222  outputFuture, 223  "AsyncFunction.apply returned null instead of a Future. " 224  + "Did you mean to return immediateFuture(null)? %s", 225  function); 226  return outputFuture; 227  } 228  229  @Override 230  void setResult(ListenableFuture<? extends O> result) { 231  setFuture(result); 232  } 233  } 234  235  /** 236  * An {@link AbstractTransformFuture} that delegates to a {@link Function} and {@link 237  * #set(Object)}. 238  */ 239  private static final class TransformFuture<I extends @Nullable Object, O extends @Nullable Object> 240  extends AbstractTransformFuture<I, O, Function<? super I, ? extends O>, O> { 241  TransformFuture( 242  ListenableFuture<? extends I> inputFuture, Function<? super I, ? extends O> function) { 243  super(inputFuture, function); 244  } 245  246  @Override 247  @ParametricNullness 248  O doTransform(Function<? super I, ? extends O> function, @ParametricNullness I input) { 249  return function.apply(input); 250  } 251  252  @Override 253  void setResult(@ParametricNullness O result) { 254  set(result); 255  } 256  } 257 }