• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.producers.internal;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.util.concurrent.Futures.catchingAsync;
21 import static com.google.common.util.concurrent.Futures.transform;
22 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
23 
24 import com.google.common.base.Function;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.collect.ImmutableSet;
27 import com.google.common.util.concurrent.AsyncFunction;
28 import com.google.common.util.concurrent.Futures;
29 import com.google.common.util.concurrent.ListenableFuture;
30 import dagger.producers.Produced;
31 import dagger.producers.Producer;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 import javax.inject.Provider;
36 
37 /**
38  * Utility methods for use in generated producer code.
39  */
40 public final class Producers {
41   /**
42    * Returns a future of {@link Produced} that represents the completion (either success or failure)
43    * of the given future. If the input future succeeds, then the resulting future also succeeds with
44    * a successful {@code Produced}; if the input future fails, then the resulting future succeeds
45    * with a failing {@code Produced}.
46    *
47    * <p>Cancelling the resulting future will propagate the cancellation to the input future; but
48    * cancelling the input future will trigger the resulting future to succeed with a failing
49    * {@code Produced}.
50    */
51   // TODO(beder): Document what happens with an InterruptedException after you figure out how to
52   // trigger one in a test.
createFutureProduced(ListenableFuture<T> future)53   public static <T> ListenableFuture<Produced<T>> createFutureProduced(ListenableFuture<T> future) {
54     return catchingAsync(
55         transform(future, Producers.<T>resultToProduced(), directExecutor()),
56         Throwable.class,
57         Producers.<T>futureFallbackForProduced(),
58         directExecutor());
59   }
60 
61   private static final Function<Object, Produced<Object>> RESULT_TO_PRODUCED =
62       new Function<Object, Produced<Object>>() {
63         @Override
64         public Produced<Object> apply(Object result) {
65           return Produced.successful(result);
66         }
67       };
68 
69   @SuppressWarnings({"unchecked", "rawtypes"}) // bivariant implementation
resultToProduced()70   private static <T> Function<T, Produced<T>> resultToProduced() {
71     return (Function) RESULT_TO_PRODUCED;
72   }
73 
74   private static final AsyncFunction<Throwable, Produced<Object>> FUTURE_FALLBACK_FOR_PRODUCED =
75       new AsyncFunction<Throwable, Produced<Object>>() {
76         @Override
77         public ListenableFuture<Produced<Object>> apply(Throwable t) throws Exception {
78           Produced<Object> produced = Produced.failed(t);
79           return Futures.immediateFuture(produced);
80         }
81       };
82 
83   @SuppressWarnings({"unchecked", "rawtypes"}) // bivariant implementation
futureFallbackForProduced()84   private static <T> AsyncFunction<Throwable, Produced<T>> futureFallbackForProduced() {
85     return (AsyncFunction) FUTURE_FALLBACK_FOR_PRODUCED;
86   }
87 
88   /**
89    * Returns a future of a {@code Set} that contains a single element: the result of the input
90    * future.
91    */
createFutureSingletonSet(ListenableFuture<T> future)92   public static <T> ListenableFuture<Set<T>> createFutureSingletonSet(ListenableFuture<T> future) {
93     return transform(
94         future,
95         new Function<T, Set<T>>() {
96           @Override
97           public Set<T> apply(T value) {
98             return ImmutableSet.of(value);
99           }
100         },
101         directExecutor());
102   }
103 
104   /**
105    * Creates a new {@code ListenableFuture} whose value is a set containing the values of all its
106    * input futures, if all succeed. If any input fails, the returned future fails immediately.
107    *
108    * <p>This is the set equivalent of {@link Futures#allAsList}.
109    */
110   public static <T> ListenableFuture<Set<T>> allAsSet(
111       Iterable<? extends ListenableFuture<? extends T>> futures) {
112     return transform(
113         Futures.allAsList(futures),
114         new Function<List<T>, Set<T>>() {
115           @Override
116           public Set<T> apply(List<T> values) {
117             return ImmutableSet.copyOf(values);
118           }
119         },
120         directExecutor());
121   }
122 
123   /**
124    * Returns a producer that immediately executes the binding logic for the given provider every
125    * time it is called.
126    */
127   public static <T> Producer<T> producerFromProvider(final Provider<T> provider) {
128     checkNotNull(provider);
129     return new CompletedProducer<T>() {
130       @Override
131       public ListenableFuture<T> get() {
132         return Futures.immediateFuture(provider.get());
133       }
134     };
135   }
136 
137   /**
138    * Returns a producer that succeeds with the given value.
139    *
140    * @deprecated Prefer the non-internal version of this method: {@link
141    * dagger.producers.Producers#immediateProducer(Object)}.
142    */
143   @Deprecated
144   public static <T> Producer<T> immediateProducer(T value) {
145     return dagger.producers.Producers.immediateProducer(value);
146   }
147 
148   /**
149    * Returns a producer that fails with the given exception.
150    *
151    * @deprecated Prefer the non-internal version of this method: {@link
152    * dagger.producers.Producers#immediateFailedProducer(Throwable)}.
153    */
154   @Deprecated
155   public static <T> Producer<T> immediateFailedProducer(Throwable throwable) {
156     return dagger.producers.Producers.immediateFailedProducer(throwable);
157   }
158 
159   /**
160    * Returns a new view of the given {@code producer} if and only if it is a {@link
161    * CancellableProducer}. Cancelling the returned producer's future will not cancel the underlying
162    * task for the given producer.
163    *
164    * @throws IllegalArgumentException if {@code producer} is not a {@code CancellableProducer}
165    */
166   public static <T> Producer<T> nonCancellationPropagatingViewOf(Producer<T> producer) {
167     // This is a hack until we change the types of Producer fields to be CancellableProducer or
168     // some other type.
169     if (producer instanceof CancellableProducer) {
170       return ((CancellableProducer<T>) producer).newDependencyView();
171     }
172     throw new IllegalArgumentException(
173         "nonCancellationPropagatingViewOf called with non-CancellableProducer: " + producer);
174   }
175 
176   /**
177    * Returns a new view of the given {@code producer} for use as an entry point in a production
178    * component, if and only if it is a {@link CancellableProducer}. When the returned producer's
179    * future is cancelled, the given {@code cancellable} will also be cancelled.
180    *
181    * @throws IllegalArgumentException if {@code producer} is not a {@code CancellableProducer}
182    */
183   public static <T> Producer<T> entryPointViewOf(
184       Producer<T> producer, CancellationListener cancellationListener) {
185     // This is a hack until we change the types of Producer fields to be CancellableProducer or
186     // some other type.
187     if (producer instanceof CancellableProducer) {
188       return ((CancellableProducer<T>) producer).newEntryPointView(cancellationListener);
189     }
190     throw new IllegalArgumentException(
191         "entryPointViewOf called with non-CancellableProducer: " + producer);
192   }
193 
194   /**
195    * Calls {@code cancel} on the given {@code producer} if it is a {@link CancellableProducer}.
196    *
197    * @throws IllegalArgumentException if {@code producer} is not a {@code CancellableProducer}
198    */
199   public static void cancel(Producer<?> producer, boolean mayInterruptIfRunning) {
200     // This is a hack until we change the types of Producer fields to be CancellableProducer or
201     // some other type.
202     if (producer instanceof CancellableProducer) {
203       ((CancellableProducer<?>) producer).cancel(mayInterruptIfRunning);
204     } else {
205       throw new IllegalArgumentException("cancel called with non-CancellableProducer: " + producer);
206     }
207   }
208 
209   private static final Producer<Map<Object, Object>> EMPTY_MAP_PRODUCER =
210       dagger.producers.Producers.<Map<Object, Object>>immediateProducer(ImmutableMap.of());
211 
212   @SuppressWarnings("unchecked") // safe contravariant cast
213   public static <K, V> Producer<Map<K, V>> emptyMapProducer() {
214     return (Producer<Map<K, V>>) (Producer) EMPTY_MAP_PRODUCER;
215   }
216 
217   /**
218    * A {@link CancellableProducer} which can't be cancelled because it represents an
219    * already-completed task.
220    */
221   private abstract static class CompletedProducer<T> implements CancellableProducer<T> {
222     @Override
223     public void cancel(boolean mayInterruptIfRunning) {}
224 
225     @Override
226     public Producer<T> newDependencyView() {
227       return this;
228     }
229 
230     @Override
231     public Producer<T> newEntryPointView(CancellationListener cancellationListener) {
232       return this;
233     }
234   }
235 
236   private Producers() {}
237 }
238