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 }