View Javadoc
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.checkState;
18  import static com.google.common.collect.Lists.newArrayListWithCapacity;
19  import static java.util.Collections.unmodifiableList;
20  
21  import com.google.common.annotations.GwtCompatible;
22  import com.google.common.base.Optional;
23  import com.google.common.collect.ImmutableCollection;
24  import com.google.common.collect.ImmutableList;
25  import com.google.common.collect.Lists;
26  import java.util.List;
27  import javax.annotation.Nullable;
28  
29  /**
30   * Aggregate future that collects (stores) results of each future.
31   */
32  @GwtCompatible(emulated = true)
33  abstract class CollectionFuture<V, C> extends AggregateFuture<V, C> {
34  
35    abstract class CollectionFutureRunningState extends RunningState {
36      private List<Optional<V>> values;
37  
38      CollectionFutureRunningState(
39          ImmutableCollection<? extends ListenableFuture<? extends V>> futures,
40          boolean allMustSucceed) {
41        super(futures, allMustSucceed, true);
42  
43        this.values =
44            futures.isEmpty()
45                ? ImmutableList.<Optional<V>>of()
46                : Lists.<Optional<V>>newArrayListWithCapacity(futures.size());
47  
48        // Populate the results list with null initially.
49        for (int i = 0; i < futures.size(); ++i) {
50          values.add(null);
51        }
52      }
53  
54      @Override
55      final void collectOneValue(boolean allMustSucceed, int index, @Nullable V returnValue) {
56        List<Optional<V>> localValues = values;
57  
58        if (localValues != null) {
59          localValues.set(index, Optional.fromNullable(returnValue));
60        } else {
61          // Some other future failed or has been cancelled, causing this one to also be cancelled or
62          // have an exception set. This should only happen if allMustSucceed is true or if the output
63          // itself has been cancelled.
64          checkState(
65              allMustSucceed || isCancelled(), "Future was done before all dependencies completed");
66        }
67      }
68  
69      @Override
70      final void handleAllCompleted() {
71        List<Optional<V>> localValues = values;
72        if (localValues != null) {
73          set(combine(localValues));
74        } else {
75          checkState(isDone());
76        }
77      }
78  
79      @Override
80      void releaseResourcesAfterFailure() {
81        super.releaseResourcesAfterFailure();
82        this.values = null;
83      }
84  
85      abstract C combine(List<Optional<V>> values);
86    }
87  
88    /** Used for {@link Futures#allAsList} and {@link Futures#successfulAsList}. */
89    static final class ListFuture<V> extends CollectionFuture<V, List<V>> {
90      ListFuture(
91          ImmutableCollection<? extends ListenableFuture<? extends V>> futures,
92          boolean allMustSucceed) {
93        init(new ListFutureRunningState(futures, allMustSucceed));
94      }
95  
96      private final class ListFutureRunningState extends CollectionFutureRunningState {
97        ListFutureRunningState(
98            ImmutableCollection<? extends ListenableFuture<? extends V>> futures,
99            boolean allMustSucceed) {
100         super(futures, allMustSucceed);
101       }
102 
103       @Override
104       public List<V> combine(List<Optional<V>> values) {
105         List<V> result = newArrayListWithCapacity(values.size());
106         for (Optional<V> element : values) {
107           result.add(element != null ? element.orNull() : null);
108         }
109         return unmodifiableList(result);
110       }
111     }
112   }
113 }