• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.monitoring;
18 
19 import static com.google.common.util.concurrent.Futures.addCallback;
20 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
21 
22 import com.google.common.util.concurrent.FutureCallback;
23 import com.google.common.util.concurrent.ListenableFuture;
24 import dagger.producers.Producer;
25 import dagger.producers.Produces;
26 
27 /**
28  * A hook for monitoring the execution of individual {@linkplain Produces producer methods}. See
29  * {@link ProductionComponentMonitor} for how to install these monitors.
30  *
31  * <p>The lifecycle of the monitor, under normal conditions, is:
32  * <ul>
33  *   <li>{@link #requested()}
34  *   <li>{@link #methodStarting()}
35  *   <li>The method is called
36  *   <li>{@link #methodFinished()}
37  *   <li>If the method returns a value, then:
38  *   <ul>
39  *     <li>{@link #succeeded(Object)} if the method returned normally; or
40  *     <li>{@link #failed(Throwable)} if the method threw an exception.
41  *   </ul>
42  *   <li>If the method returns a future, then:
43  *   <ul>
44  *     <li>{@link #succeeded(Object)} if the method returned normally, and the future succeeded; or
45  *     <li>{@link #failed(Throwable)} if the method threw an exception, or returned normally and the
46  *         future failed.
47  *   </ul>
48  * </ul>
49  *
50  * <p>If any input to the monitored producer fails, {@link #failed(Throwable)} will be called
51  * immediately with the failed input's exception. If more than one input fails, an arbitrary failed
52  * input's exception is used.
53  *
54  * <p>For example, given an entry point A that depends on B, which depends on C, when the entry
55  * point A is called, this will trigger the following sequence of events, assuming all methods and
56  * futures complete successfully:
57  * <ul>
58  *   <li>A requested
59  *   <li>B requested
60  *   <li>C requested
61  *   <li>C methodStarting
62  *   <li>C methodFinished
63  *   <li>C succeeded
64  *   <li>B methodStarting
65  *   <li>B methodFinished
66  *   <li>B succeeded
67  *   <li>A methodStarting
68  *   <li>A methodFinished
69  *   <li>A succeeded
70  * </ul>
71  *
72  * <p>If any of the monitor's methods throw, then the exception will be logged and processing will
73  * continue unaffected.
74  *
75  * @since 2.1
76  */
77 public abstract class ProducerMonitor {
78   /**
79    * Called when the producer's output is requested; that is, when the first method is called that
80    * requires the production of this producer's output.
81    *
82    * <p>Note that if a method depends on {@code Producer<T>}, then this does not count as requesting
83    * {@code T}; that is only triggered by calling {@link Producer#get()}.
84    *
85    * <p>Depending on how this producer is requested, the following threading constraints are
86    * guaranteed:
87    *
88    * <ol>
89    *   <li>If the producer is requested directly by a method on a component, then {@code requested}
90    *       will be called on the same thread as the component method call.
91    *   <li>If the producer is requested by value from another producer (i.e., injected as {@code T}
92    *       or {@code Produced<T>}), then {@code requested} will be called from the same thread as
93    *       the other producer's {@code requested}.
94    *   <li>If the producer is requested by calling {@link Producer#get()}, then {@code requested}
95    *       will be called from the same thread as that {@code get()} call.
96    * </ol>
97    *
98    * <p>When multiple monitors are installed, the order that each monitor will call this method is
99    * unspecified, but will remain consistent throughout the course of the execution of a component.
100    *
101    * <p>This implementation is a no-op.
102    */
requested()103   public void requested() {}
104 
105   /**
106    * Called when all of the producer's inputs are available. This is called regardless of whether
107    * the inputs have succeeded or not; when the inputs have succeeded, this is called prior to
108    * scheduling the method on the executor, and if an input has failed and the producer will be
109    * skipped, this method will be called before {@link #failed(Throwable)} is called.
110    *
111    * <p>When multiple monitors are installed, the order that each monitor will call this method is
112    * unspecified, but will remain consistent throughout the course of the execution of a component.
113    *
114    * <p>This implementation is a no-op.
115    */
ready()116   public void ready() {}
117 
118   /**
119    * Called when the producer method is about to start executing. This will be called from the same
120    * thread as the producer method itself.
121    *
122    * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
123    * calls to {@link #requested()}.
124    *
125    * <p>This implementation is a no-op.
126    */
methodStarting()127   public void methodStarting() {}
128 
129   /**
130    * Called when the producer method has finished executing. This will be called from the same
131    * thread as {@link #methodStarting()} and the producer method itself.
132    *
133    * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
134    * calls to {@link #requested()}.
135    *
136    * <p>This implementation is a no-op.
137    */
methodFinished()138   public void methodFinished() {}
139 
140   /**
141    * Called when the producer’s future has completed successfully with a value.
142    *
143    * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
144    * calls to {@link #requested()}.
145    *
146    * <p>This implementation is a no-op.
147    */
succeeded(@uppressWarnings"unused") Object value)148   public void succeeded(@SuppressWarnings("unused") Object value) {}
149 
150   /**
151    * Called when the producer's future has failed with an exception.
152    *
153    * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
154    * calls to {@link #requested()}.
155    *
156    * <p>This implementation is a no-op.
157    */
failed(@uppressWarnings"unused") Throwable t)158   public void failed(@SuppressWarnings("unused") Throwable t) {}
159 
160   /**
161    * Adds this monitor's completion methods as a callback to the future. This is only intended to be
162    * overridden in the framework!
163    */
addCallbackTo(ListenableFuture<T> future)164   public <T> void addCallbackTo(ListenableFuture<T> future) {
165     addCallback(
166         future,
167         new FutureCallback<T>() {
168           @Override
169           public void onSuccess(T value) {
170             succeeded(value);
171           }
172 
173           @Override
174           public void onFailure(Throwable t) {
175             failed(t);
176           }
177         },
178         directExecutor());
179   }
180 
181   private static final ProducerMonitor NO_OP =
182       new ProducerMonitor() {
183         @Override
184         public <T> void addCallbackTo(ListenableFuture<T> future) {
185           // overridden to avoid adding a do-nothing callback
186         }
187       };
188 
189   /** Returns a monitor that does no monitoring. */
noOp()190   public static ProducerMonitor noOp() {
191     return NO_OP;
192   }
193 }
194