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