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

Class Method, % Line, %
CombinedFuture 0% (0/6) 0% (0/16)
CombinedFuture$AsyncCallableInterruptibleTask 0% (0/4) 0% (0/7)
CombinedFuture$CallableInterruptibleTask 0% (0/4) 0% (0/6)
CombinedFuture$CombinedFutureInterruptibleTask 0% (0/5) 0% (0/15)
Total 0% (0/19) 0% (0/44)


1 /* 2  * Copyright (C) 2015 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.AggregateFuture.ReleaseResourcesReason.OUTPUT_FUTURE_DONE; 19  20 import com.google.common.annotations.GwtCompatible; 21 import com.google.common.collect.ImmutableCollection; 22 import com.google.j2objc.annotations.WeakOuter; 23 import java.util.concurrent.Callable; 24 import java.util.concurrent.CancellationException; 25 import java.util.concurrent.ExecutionException; 26 import java.util.concurrent.Executor; 27 import java.util.concurrent.RejectedExecutionException; 28 import javax.annotation.CheckForNull; 29 import org.checkerframework.checker.nullness.qual.Nullable; 30  31 /** Aggregate future that computes its value by calling a callable. */ 32 @GwtCompatible 33 @ElementTypesAreNonnullByDefault 34 final class CombinedFuture<V extends @Nullable Object> 35  extends AggregateFuture<@Nullable Object, V> { 36  @CheckForNull private CombinedFutureInterruptibleTask<?> task; 37  38  CombinedFuture( 39  ImmutableCollection<? extends ListenableFuture<?>> futures, 40  boolean allMustSucceed, 41  Executor listenerExecutor, 42  AsyncCallable<V> callable) { 43  super(futures, allMustSucceed, false); 44  this.task = new AsyncCallableInterruptibleTask(callable, listenerExecutor); 45  init(); 46  } 47  48  CombinedFuture( 49  ImmutableCollection<? extends ListenableFuture<?>> futures, 50  boolean allMustSucceed, 51  Executor listenerExecutor, 52  Callable<V> callable) { 53  super(futures, allMustSucceed, false); 54  this.task = new CallableInterruptibleTask(callable, listenerExecutor); 55  init(); 56  } 57  58  @Override 59  void collectOneValue(int index, @CheckForNull Object returnValue) {} 60  61  @Override 62  void handleAllCompleted() { 63  CombinedFutureInterruptibleTask<?> localTask = task; 64  if (localTask != null) { 65  localTask.execute(); 66  } 67  } 68  69  @Override 70  void releaseResources(ReleaseResourcesReason reason) { 71  super.releaseResources(reason); 72  /* 73  * If the output future is done, then it won't need to interrupt the task later, so it can clear 74  * its reference to it. 75  * 76  * If the output future is *not* done, then the task field will be cleared after the task runs 77  * or after the output future is done, whichever comes first. 78  */ 79  if (reason == OUTPUT_FUTURE_DONE) { 80  this.task = null; 81  } 82  } 83  84  @Override 85  protected void interruptTask() { 86  CombinedFutureInterruptibleTask<?> localTask = task; 87  if (localTask != null) { 88  localTask.interruptTask(); 89  } 90  } 91  92  @WeakOuter 93  private abstract class CombinedFutureInterruptibleTask<T extends @Nullable Object> 94  extends InterruptibleTask<T> { 95  private final Executor listenerExecutor; 96  97  CombinedFutureInterruptibleTask(Executor listenerExecutor) { 98  this.listenerExecutor = checkNotNull(listenerExecutor); 99  } 100  101  @Override 102  final boolean isDone() { 103  return CombinedFuture.this.isDone(); 104  } 105  106  final void execute() { 107  try { 108  listenerExecutor.execute(this); 109  } catch (RejectedExecutionException e) { 110  CombinedFuture.this.setException(e); 111  } 112  } 113  114  @Override 115  final void afterRanInterruptiblySuccess(@ParametricNullness T result) { 116  /* 117  * The future no longer needs to interrupt this task, so it no longer needs a reference to it. 118  * 119  * TODO(cpovirk): It might be nice for our InterruptibleTask subclasses to null out their 120  * `callable` fields automatically. That would make it less important for us to null out the 121  * reference to `task` here (though it's still nice to do so in case our reference to the 122  * executor keeps it alive). Ideally, nulling out `callable` would be the responsibility of 123  * InterruptibleTask itself so that its other subclasses also benefit. (Handling `callable` in 124  * InterruptibleTask itself might also eliminate some of the existing boilerplate for, e.g., 125  * pendingToString().) 126  */ 127  CombinedFuture.this.task = null; 128  129  setValue(result); 130  } 131  132  @Override 133  final void afterRanInterruptiblyFailure(Throwable error) { 134  // See afterRanInterruptiblySuccess. 135  CombinedFuture.this.task = null; 136  137  if (error instanceof ExecutionException) { 138  /* 139  * Cast to ExecutionException to satisfy our nullness checker, which (unsoundly but 140  * *usually* safely) assumes that getCause() returns non-null on an ExecutionException. 141  */ 142  CombinedFuture.this.setException(((ExecutionException) error).getCause()); 143  } else if (error instanceof CancellationException) { 144  cancel(false); 145  } else { 146  CombinedFuture.this.setException(error); 147  } 148  } 149  150  abstract void setValue(@ParametricNullness T value); 151  } 152  153  @WeakOuter 154  private final class AsyncCallableInterruptibleTask 155  extends CombinedFutureInterruptibleTask<ListenableFuture<V>> { 156  private final AsyncCallable<V> callable; 157  158  AsyncCallableInterruptibleTask(AsyncCallable<V> callable, Executor listenerExecutor) { 159  super(listenerExecutor); 160  this.callable = checkNotNull(callable); 161  } 162  163  @Override 164  ListenableFuture<V> runInterruptibly() throws Exception { 165  ListenableFuture<V> result = callable.call(); 166  return checkNotNull( 167  result, 168  "AsyncCallable.call returned null instead of a Future. " 169  + "Did you mean to return immediateFuture(null)? %s", 170  callable); 171  } 172  173  @Override 174  void setValue(ListenableFuture<V> value) { 175  CombinedFuture.this.setFuture(value); 176  } 177  178  @Override 179  String toPendingString() { 180  return callable.toString(); 181  } 182  } 183  184  @WeakOuter 185  private final class CallableInterruptibleTask extends CombinedFutureInterruptibleTask<V> { 186  private final Callable<V> callable; 187  188  CallableInterruptibleTask(Callable<V> callable, Executor listenerExecutor) { 189  super(listenerExecutor); 190  this.callable = checkNotNull(callable); 191  } 192  193  @Override 194  @ParametricNullness 195  V runInterruptibly() throws Exception { 196  return callable.call(); 197  } 198  199  @Override 200  void setValue(@ParametricNullness V value) { 201  CombinedFuture.this.set(value); 202  } 203  204  @Override 205  String toPendingString() { 206  return callable.toString(); 207  } 208  } 209 }