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