• 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.internal;
18 
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.Iterables;
21 import dagger.producers.monitoring.ProducerMonitor;
22 import dagger.producers.monitoring.ProducerToken;
23 import dagger.producers.monitoring.ProductionComponentMonitor;
24 import java.util.Collection;
25 import java.util.Set;
26 import java.util.logging.Level;
27 import java.util.logging.Logger;
28 import javax.inject.Provider;
29 
30 /**
31  * Utility methods relating to monitoring, for use in generated producers code.
32  */
33 public final class Monitors {
34   private static final Logger logger = Logger.getLogger(Monitors.class.getName());
35 
36   /**
37    * Returns a monitor factory that delegates to the given factories, and ensures that any method
38    * called on this object, even transitively, does not throw a {@link RuntimeException} or return
39    * null.
40    *
41    * <p>If the delegate monitors throw an {@link Error}, then that will escape this monitor
42    * implementation. Errors are treated as unrecoverable conditions, and may cause the entire
43    * component's execution to fail.
44    */
delegatingProductionComponentMonitorFactory( Collection<? extends ProductionComponentMonitor.Factory> factories)45   public static ProductionComponentMonitor.Factory delegatingProductionComponentMonitorFactory(
46       Collection<? extends ProductionComponentMonitor.Factory> factories) {
47     if (factories.isEmpty()) {
48       return ProductionComponentMonitor.Factory.noOp();
49     } else if (factories.size() == 1) {
50       return new NonThrowingProductionComponentMonitor.Factory(Iterables.getOnlyElement(factories));
51     } else {
52       return new DelegatingProductionComponentMonitor.Factory(factories);
53     }
54   }
55 
56   /**
57    * Creates a new monitor for the given component, from a set of monitor factories. This will not
58    * throw a {@link RuntimeException} or return null.
59    */
createMonitorForComponent( Provider<?> componentProvider, Provider<Set<ProductionComponentMonitor.Factory>> monitorFactorySetProvider)60   public static ProductionComponentMonitor createMonitorForComponent(
61       Provider<?> componentProvider,
62       Provider<Set<ProductionComponentMonitor.Factory>> monitorFactorySetProvider) {
63     try {
64       ProductionComponentMonitor.Factory factory =
65           delegatingProductionComponentMonitorFactory(monitorFactorySetProvider.get());
66       return factory.create(componentProvider.get());
67     } catch (RuntimeException e) {
68       logger.log(Level.SEVERE, "RuntimeException while constructing monitor factories.", e);
69       return ProductionComponentMonitor.noOp();
70     }
71   }
72 
73   /**
74    * A component monitor that delegates to a single monitor, and catches and logs all exceptions
75    * that the delegate throws.
76    */
77   private static final class NonThrowingProductionComponentMonitor
78       extends ProductionComponentMonitor {
79     private final ProductionComponentMonitor delegate;
80 
NonThrowingProductionComponentMonitor(ProductionComponentMonitor delegate)81     NonThrowingProductionComponentMonitor(ProductionComponentMonitor delegate) {
82       this.delegate = delegate;
83     }
84 
85     @Override
producerMonitorFor(ProducerToken token)86     public ProducerMonitor producerMonitorFor(ProducerToken token) {
87       try {
88         ProducerMonitor monitor = delegate.producerMonitorFor(token);
89         return monitor == null ? ProducerMonitor.noOp() : new NonThrowingProducerMonitor(monitor);
90       } catch (RuntimeException e) {
91         logProducerMonitorForException(e, delegate, token);
92         return ProducerMonitor.noOp();
93       }
94     }
95 
96     static final class Factory extends ProductionComponentMonitor.Factory {
97       private final ProductionComponentMonitor.Factory delegate;
98 
Factory(ProductionComponentMonitor.Factory delegate)99       Factory(ProductionComponentMonitor.Factory delegate) {
100         this.delegate = delegate;
101       }
102 
103       @Override
create(Object component)104       public ProductionComponentMonitor create(Object component) {
105         try {
106           ProductionComponentMonitor monitor = delegate.create(component);
107           return monitor == null
108               ? ProductionComponentMonitor.noOp()
109               : new NonThrowingProductionComponentMonitor(monitor);
110         } catch (RuntimeException e) {
111           logCreateException(e, delegate, component);
112           return ProductionComponentMonitor.noOp();
113         }
114       }
115     }
116   }
117 
118   /**
119    * A producer monitor that delegates to a single monitor, and catches and logs all exceptions
120    * that the delegate throws.
121    */
122   private static final class NonThrowingProducerMonitor extends ProducerMonitor {
123     private final ProducerMonitor delegate;
124 
NonThrowingProducerMonitor(ProducerMonitor delegate)125     NonThrowingProducerMonitor(ProducerMonitor delegate) {
126       this.delegate = delegate;
127     }
128 
129     @Override
requested()130     public void requested() {
131       try {
132         delegate.requested();
133       } catch (RuntimeException e) {
134         logProducerMonitorMethodException(e, delegate, "requested");
135       }
136     }
137 
138     @Override
ready()139     public void ready() {
140       try {
141         delegate.ready();
142       } catch (RuntimeException e) {
143         logProducerMonitorMethodException(e, delegate, "ready");
144       }
145     }
146 
147     @Override
methodStarting()148     public void methodStarting() {
149       try {
150         delegate.methodStarting();
151       } catch (RuntimeException e) {
152         logProducerMonitorMethodException(e, delegate, "methodStarting");
153       }
154     }
155 
156     @Override
methodFinished()157     public void methodFinished() {
158       try {
159         delegate.methodFinished();
160       } catch (RuntimeException e) {
161         logProducerMonitorMethodException(e, delegate, "methodFinished");
162       }
163     }
164 
165     @Override
succeeded(Object o)166     public void succeeded(Object o) {
167       try {
168         delegate.succeeded(o);
169       } catch (RuntimeException e) {
170         logProducerMonitorArgMethodException(e, delegate, "succeeded", o);
171       }
172     }
173 
174     @Override
failed(Throwable t)175     public void failed(Throwable t) {
176       try {
177         delegate.failed(t);
178       } catch (RuntimeException e) {
179         logProducerMonitorArgMethodException(e, delegate, "failed", t);
180       }
181     }
182   }
183 
184   /**
185    * A component monitor that delegates to several monitors, and catches and logs all exceptions
186    * that the delegates throw.
187    */
188   private static final class DelegatingProductionComponentMonitor
189       extends ProductionComponentMonitor {
190     private final ImmutableList<ProductionComponentMonitor> delegates;
191 
DelegatingProductionComponentMonitor(ImmutableList<ProductionComponentMonitor> delegates)192     DelegatingProductionComponentMonitor(ImmutableList<ProductionComponentMonitor> delegates) {
193       this.delegates = delegates;
194     }
195 
196     @Override
producerMonitorFor(ProducerToken token)197     public ProducerMonitor producerMonitorFor(ProducerToken token) {
198       ImmutableList.Builder<ProducerMonitor> monitorsBuilder = ImmutableList.builder();
199       for (ProductionComponentMonitor delegate : delegates) {
200         try {
201           ProducerMonitor monitor = delegate.producerMonitorFor(token);
202           if (monitor != null) {
203             monitorsBuilder.add(monitor);
204           }
205         } catch (RuntimeException e) {
206           logProducerMonitorForException(e, delegate, token);
207         }
208       }
209       ImmutableList<ProducerMonitor> monitors = monitorsBuilder.build();
210       if (monitors.isEmpty()) {
211         return ProducerMonitor.noOp();
212       } else if (monitors.size() == 1) {
213         return new NonThrowingProducerMonitor(Iterables.getOnlyElement(monitors));
214       } else {
215         return new DelegatingProducerMonitor(monitors);
216       }
217     }
218 
219     static final class Factory extends ProductionComponentMonitor.Factory {
220       private final ImmutableList<? extends ProductionComponentMonitor.Factory> delegates;
221 
Factory(Iterable<? extends ProductionComponentMonitor.Factory> delegates)222       Factory(Iterable<? extends ProductionComponentMonitor.Factory> delegates) {
223         this.delegates = ImmutableList.copyOf(delegates);
224       }
225 
226       @Override
create(Object component)227       public ProductionComponentMonitor create(Object component) {
228         ImmutableList.Builder<ProductionComponentMonitor> monitorsBuilder = ImmutableList.builder();
229         for (ProductionComponentMonitor.Factory delegate : delegates) {
230           try {
231             ProductionComponentMonitor monitor = delegate.create(component);
232             if (monitor != null) {
233               monitorsBuilder.add(monitor);
234             }
235           } catch (RuntimeException e) {
236             logCreateException(e, delegate, component);
237           }
238         }
239         ImmutableList<ProductionComponentMonitor> monitors = monitorsBuilder.build();
240         if (monitors.isEmpty()) {
241           return ProductionComponentMonitor.noOp();
242         } else if (monitors.size() == 1) {
243           return new NonThrowingProductionComponentMonitor(Iterables.getOnlyElement(monitors));
244         } else {
245           return new DelegatingProductionComponentMonitor(monitors);
246         }
247       }
248     }
249   }
250 
251   /**
252    * A producer monitor that delegates to several monitors, and catches and logs all exceptions
253    * that the delegates throw.
254    */
255   private static final class DelegatingProducerMonitor extends ProducerMonitor {
256     private final ImmutableList<ProducerMonitor> delegates;
257 
DelegatingProducerMonitor(ImmutableList<ProducerMonitor> delegates)258     DelegatingProducerMonitor(ImmutableList<ProducerMonitor> delegates) {
259       this.delegates = delegates;
260     }
261 
262     @Override
requested()263     public void requested() {
264       for (ProducerMonitor delegate : delegates) {
265         try {
266           delegate.requested();
267         } catch (RuntimeException e) {
268           logProducerMonitorMethodException(e, delegate, "requested");
269         }
270       }
271     }
272 
273     @Override
ready()274     public void ready() {
275       for (ProducerMonitor delegate : delegates) {
276         try {
277           delegate.ready();
278         } catch (RuntimeException e) {
279           logProducerMonitorMethodException(e, delegate, "ready");
280         }
281       }
282     }
283 
284     @Override
methodStarting()285     public void methodStarting() {
286       for (ProducerMonitor delegate : delegates) {
287         try {
288           delegate.methodStarting();
289         } catch (RuntimeException e) {
290           logProducerMonitorMethodException(e, delegate, "methodStarting");
291         }
292       }
293     }
294 
295     @Override
methodFinished()296     public void methodFinished() {
297       for (ProducerMonitor delegate : delegates.reverse()) {
298         try {
299           delegate.methodFinished();
300         } catch (RuntimeException e) {
301           logProducerMonitorMethodException(e, delegate, "methodFinished");
302         }
303       }
304     }
305 
306     @Override
succeeded(Object o)307     public void succeeded(Object o) {
308       for (ProducerMonitor delegate : delegates.reverse()) {
309         try {
310           delegate.succeeded(o);
311         } catch (RuntimeException e) {
312           logProducerMonitorArgMethodException(e, delegate, "succeeded", o);
313         }
314       }
315     }
316 
317     @Override
failed(Throwable t)318     public void failed(Throwable t) {
319       for (ProducerMonitor delegate : delegates.reverse()) {
320         try {
321           delegate.failed(t);
322         } catch (RuntimeException e) {
323           logProducerMonitorArgMethodException(e, delegate, "failed", t);
324         }
325       }
326     }
327   }
328 
329   /** Returns a provider of a no-op component monitor. */
noOpProductionComponentMonitorProvider()330   public static Provider<ProductionComponentMonitor> noOpProductionComponentMonitorProvider() {
331     return NO_OP_PRODUCTION_COMPONENT_MONITOR_PROVIDER;
332   }
333 
334   private static final Provider<ProductionComponentMonitor>
335       NO_OP_PRODUCTION_COMPONENT_MONITOR_PROVIDER =
336           new Provider<ProductionComponentMonitor>() {
337             @Override
338             public ProductionComponentMonitor get() {
339               return ProductionComponentMonitor.noOp();
340             }
341           };
342 
logCreateException( RuntimeException e, ProductionComponentMonitor.Factory factory, Object component)343   private static void logCreateException(
344       RuntimeException e, ProductionComponentMonitor.Factory factory, Object component) {
345     logger.log(
346         Level.SEVERE,
347         "RuntimeException while calling ProductionComponentMonitor.Factory.create on factory "
348             + factory
349             + " with component "
350             + component,
351         e);
352   }
353 
logProducerMonitorForException( RuntimeException e, ProductionComponentMonitor monitor, ProducerToken token)354   private static void logProducerMonitorForException(
355       RuntimeException e, ProductionComponentMonitor monitor, ProducerToken token) {
356     logger.log(
357         Level.SEVERE,
358         "RuntimeException while calling ProductionComponentMonitor.producerMonitorFor on monitor "
359             + monitor
360             + " with token "
361             + token,
362         e);
363   }
364 
logProducerMonitorMethodException( RuntimeException e, ProducerMonitor monitor, String method)365   private static void logProducerMonitorMethodException(
366       RuntimeException e, ProducerMonitor monitor, String method) {
367     logger.log(
368         Level.SEVERE,
369         "RuntimeException while calling ProducerMonitor." + method + " on monitor " + monitor,
370         e);
371   }
372 
logProducerMonitorArgMethodException( RuntimeException e, ProducerMonitor monitor, String method, Object arg)373   private static void logProducerMonitorArgMethodException(
374       RuntimeException e, ProducerMonitor monitor, String method, Object arg) {
375     logger.log(
376         Level.SEVERE,
377         "RuntimeException while calling ProducerMonitor."
378             + method
379             + " on monitor "
380             + monitor
381             + " with "
382             + arg,
383         e);
384   }
385 
Monitors()386   private Monitors() {}
387 }
388