1/*
2 * Copyright (C) 2015 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 */
16package dagger.producers.monitoring;
17
18import com.google.common.util.concurrent.FutureCallback;
19import com.google.common.util.concurrent.Futures;
20import com.google.common.util.concurrent.ListenableFuture;
21import dagger.producers.Produces;
22
23/**
24 * A hook for monitoring the execution of individual {@linkplain Produces producer methods}. See
25 * {@link ProductionComponentMonitor} for how to install these monitors.
26 *
27 * <p>The lifecycle of the monitor, under normal conditions, is:
28 * <ul>
29 *   <li>{@link #methodStarting()}
30 *   <li>The method is called
31 *   <li>{@link #methodFinished()}
32 *   <li>If the method returns a value, then:
33 *   <ul>
34 *     <li>{@link #succeeded(Object)} if the method returned normally; or
35 *     <li>{@link #failed(Throwable)} if the method threw an exception.
36 *   </ul>
37 *   <li>If the method returns a future, then:
38 *   <ul>
39 *     <li>{@link #succeeded(Object)} if the method returned normally, and the future succeeded; or
40 *     <li>{@link #failed(Throwable)} if the method threw an exception, or returned normally and the
41 *         future failed.
42 *   </ul>
43 * </ul>
44 *
45 * <p>If any input to the monitored producer fails, {@link #failed(Throwable)} will be called
46 * immediately with the failed input's exception. If more than one input fails, an arbitrary failed
47 * input's exception is used.
48 *
49 * <p>If any of the monitor's methods throw, then the exception will be logged and processing will
50 * continue unaffected.
51 *
52 * @author Jesse Beder
53 */
54public abstract class ProducerMonitor {
55  /**
56   * Called when the producer method is about to start executing.
57   *
58   * <p>When multiple monitors are installed, the order that each monitor will call this method is
59   * unspecified, but will remain consistent throughout the course of the execution of a component.
60   */
61  public void methodStarting() {}
62
63  /**
64   * Called when the producer method has finished executing.
65   *
66   * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
67   * calls to {@link #methodStarting()}.
68   */
69  public void methodFinished() {}
70
71  /**
72   * Called when the producer’s future has completed successfully with a value.
73   *
74   * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
75   * calls to {@link #methodStarting()}.
76   */
77  public void succeeded(Object o) {}
78
79  /**
80   * Called when the producer's future has failed with an exception.
81   *
82   * <p>When multiple monitors are installed, calls to this method will be in the reverse order from
83   * calls to {@link #methodStarting()}.
84   */
85  public void failed(Throwable t) {}
86
87  /**
88   * Adds this monitor's completion methods as a callback to the future. This is only intended to be
89   * overridden in the framework!
90   */
91  public <T> void addCallbackTo(ListenableFuture<T> future) {
92    Futures.addCallback(
93        future,
94        new FutureCallback<T>() {
95          @Override
96          public void onSuccess(T value) {
97            succeeded(value);
98          }
99
100          @Override
101          public void onFailure(Throwable t) {
102            failed(t);
103          }
104        });
105  }
106}
107