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