1 /*
2  * Copyright (C) 2014 Google Inc.
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 package dagger.producers;
17 
18 import com.google.common.base.Objects;
19 import dagger.internal.Beta;
20 import java.util.concurrent.ExecutionException;
21 import javax.annotation.Nullable;
22 
23 import static com.google.common.base.Preconditions.checkNotNull;
24 
25 /**
26  * An interface that represents the result of a {@linkplain Producer production} of type {@code T},
27  * or an exception that was thrown during that production. For any type {@code T} that can be
28  * injected, you can also inject {@code Produced<T>}, which enables handling of any exceptions that
29  * were thrown during the production of {@code T}.
30  *
31  * <p>For example: <pre><code>
32  *   {@literal @}Produces Html getResponse(
33  *       UserInfo criticalInfo, {@literal Produced<ExtraInfo>} noncriticalInfo) {
34  *     try {
35  *       return new Html(criticalInfo, noncriticalInfo.get());
36  *     } catch (ExecutionException e) {
37  *       logger.warning(e, "Noncritical info");
38  *       return new Html(criticalInfo);
39  *     }
40  *   }
41  * </code></pre>
42  *
43  * @author Jesse Beder
44  */
45 @Beta
46 public abstract class Produced<T> {
47   /**
48    * Returns the result of a production.
49    *
50    * @throws ExecutionException if the production threw an exception
51    */
get()52   public abstract T get() throws ExecutionException;
53 
54   /**
55    * Two {@code Produced} objects compare equal if both are successful with equal values, or both
56    * are failed with equal exceptions.
57    */
58   @Override
equals(Object o)59   public abstract boolean equals(Object o);
60 
61   /** Returns an appropriate hash code to match {@link #equals). */
62   @Override
hashCode()63   public abstract int hashCode();
64 
65   /** Returns a successful {@code Produced}, whose {@link #get} will return the given value. */
successful(@ullable T value)66   public static <T> Produced<T> successful(@Nullable T value) {
67     return new Successful<T>(value);
68   }
69 
70   /**
71    * Returns a failed {@code Produced}, whose {@link #get} will throw an
72    * {@code ExecutionException} with the given cause.
73    */
failed(Throwable throwable)74   public static <T> Produced<T> failed(Throwable throwable) {
75     return new Failed<T>(checkNotNull(throwable));
76   }
77 
78   private static final class Successful<T> extends Produced<T> {
79     @Nullable private final T value;
80 
Successful(@ullable T value)81     private Successful(@Nullable T value) {
82       this.value = value;
83     }
84 
get()85     @Override public T get() {
86       return value;
87     }
88 
equals(Object o)89     @Override public boolean equals(Object o) {
90       if (o == this) {
91         return true;
92       } else if (o instanceof Successful) {
93         Successful<?> that = (Successful<?>) o;
94         return Objects.equal(this.value, that.value);
95       } else {
96         return false;
97       }
98     }
99 
hashCode()100     @Override public int hashCode() {
101       return value == null ? 0 : value.hashCode();
102     }
103   }
104 
105   private static final class Failed<T> extends Produced<T> {
106     private final Throwable throwable;
107 
Failed(Throwable throwable)108     private Failed(Throwable throwable) {
109       this.throwable = checkNotNull(throwable);
110     }
111 
get()112     @Override public T get() throws ExecutionException {
113       throw new ExecutionException(throwable);
114     }
115 
equals(Object o)116     @Override public boolean equals(Object o) {
117       if (o == this) {
118         return true;
119       } else if (o instanceof Failed) {
120         Failed<?> that = (Failed<?>) o;
121         return this.throwable.equals(that.throwable);
122       } else {
123         return false;
124       }
125     }
126 
hashCode()127     @Override public int hashCode() {
128       return throwable.hashCode();
129     }
130   }
131 
Produced()132   private Produced() {}
133 }
134