194 lines
7.0 KiB
Java
194 lines
7.0 KiB
Java
|
|
/*
|
|||
|
|
* Copyright (C) 2015 The Dagger Authors.
|
|||
|
|
*
|
|||
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
|
* you may not use this file except in compliance with the License.
|
|||
|
|
* You may obtain a copy of the License at
|
|||
|
|
*
|
|||
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
*
|
|||
|
|
* Unless required by applicable law or agreed to in writing, software
|
|||
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
|
* See the License for the specific language governing permissions and
|
|||
|
|
* limitations under the License.
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
package dagger.producers.monitoring;
|
|||
|
|
|
|||
|
|
import static com.google.common.util.concurrent.Futures.addCallback;
|
|||
|
|
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
|
|||
|
|
|
|||
|
|
import com.google.common.util.concurrent.FutureCallback;
|
|||
|
|
import com.google.common.util.concurrent.ListenableFuture;
|
|||
|
|
import dagger.producers.Producer;
|
|||
|
|
import dagger.producers.Produces;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* A hook for monitoring the execution of individual {@linkplain Produces producer methods}. See
|
|||
|
|
* {@link ProductionComponentMonitor} for how to install these monitors.
|
|||
|
|
*
|
|||
|
|
* <p>The lifecycle of the monitor, under normal conditions, is:
|
|||
|
|
* <ul>
|
|||
|
|
* <li>{@link #requested()}
|
|||
|
|
* <li>{@link #methodStarting()}
|
|||
|
|
* <li>The method is called
|
|||
|
|
* <li>{@link #methodFinished()}
|
|||
|
|
* <li>If the method returns a value, then:
|
|||
|
|
* <ul>
|
|||
|
|
* <li>{@link #succeeded(Object)} if the method returned normally; or
|
|||
|
|
* <li>{@link #failed(Throwable)} if the method threw an exception.
|
|||
|
|
* </ul>
|
|||
|
|
* <li>If the method returns a future, then:
|
|||
|
|
* <ul>
|
|||
|
|
* <li>{@link #succeeded(Object)} if the method returned normally, and the future succeeded; or
|
|||
|
|
* <li>{@link #failed(Throwable)} if the method threw an exception, or returned normally and the
|
|||
|
|
* future failed.
|
|||
|
|
* </ul>
|
|||
|
|
* </ul>
|
|||
|
|
*
|
|||
|
|
* <p>If any input to the monitored producer fails, {@link #failed(Throwable)} will be called
|
|||
|
|
* immediately with the failed input's exception. If more than one input fails, an arbitrary failed
|
|||
|
|
* input's exception is used.
|
|||
|
|
*
|
|||
|
|
* <p>For example, given an entry point A that depends on B, which depends on C, when the entry
|
|||
|
|
* point A is called, this will trigger the following sequence of events, assuming all methods and
|
|||
|
|
* futures complete successfully:
|
|||
|
|
* <ul>
|
|||
|
|
* <li>A requested
|
|||
|
|
* <li>B requested
|
|||
|
|
* <li>C requested
|
|||
|
|
* <li>C methodStarting
|
|||
|
|
* <li>C methodFinished
|
|||
|
|
* <li>C succeeded
|
|||
|
|
* <li>B methodStarting
|
|||
|
|
* <li>B methodFinished
|
|||
|
|
* <li>B succeeded
|
|||
|
|
* <li>A methodStarting
|
|||
|
|
* <li>A methodFinished
|
|||
|
|
* <li>A succeeded
|
|||
|
|
* </ul>
|
|||
|
|
*
|
|||
|
|
* <p>If any of the monitor's methods throw, then the exception will be logged and processing will
|
|||
|
|
* continue unaffected.
|
|||
|
|
*
|
|||
|
|
* @since 2.1
|
|||
|
|
*/
|
|||
|
|
public abstract class ProducerMonitor {
|
|||
|
|
/**
|
|||
|
|
* Called when the producer's output is requested; that is, when the first method is called that
|
|||
|
|
* requires the production of this producer's output.
|
|||
|
|
*
|
|||
|
|
* <p>Note that if a method depends on {@code Producer<T>}, then this does not count as requesting
|
|||
|
|
* {@code T}; that is only triggered by calling {@link Producer#get()}.
|
|||
|
|
*
|
|||
|
|
* <p>Depending on how this producer is requested, the following threading constraints are
|
|||
|
|
* guaranteed:
|
|||
|
|
*
|
|||
|
|
* <ol>
|
|||
|
|
* <li>If the producer is requested directly by a method on a component, then {@code requested}
|
|||
|
|
* will be called on the same thread as the component method call.
|
|||
|
|
* <li>If the producer is requested by value from another producer (i.e., injected as {@code T}
|
|||
|
|
* or {@code Produced<T>}), then {@code requested} will be called from the same thread as
|
|||
|
|
* the other producer's {@code requested}.
|
|||
|
|
* <li>If the producer is requested by calling {@link Producer#get()}, then {@code requested}
|
|||
|
|
* will be called from the same thread as that {@code get()} call.
|
|||
|
|
* </ol>
|
|||
|
|
*
|
|||
|
|
* <p>When multiple monitors are installed, the order that each monitor will call this method is
|
|||
|
|
* unspecified, but will remain consistent throughout the course of the execution of a component.
|
|||
|
|
*
|
|||
|
|
* <p>This implementation is a no-op.
|
|||
|
|
*/
|
|||
|
|
public void requested() {}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Called when all of the producer's inputs are available. This is called regardless of whether
|
|||
|
|
* the inputs have succeeded or not; when the inputs have succeeded, this is called prior to
|
|||
|
|
* scheduling the method on the executor, and if an input has failed and the producer will be
|
|||
|
|
* skipped, this method will be called before {@link #failed(Throwable)} is called.
|
|||
|
|
*
|
|||
|
|
* <p>When multiple monitors are installed, the order that each monitor will call this method is
|
|||
|
|
* unspecified, but will remain consistent throughout the course of the execution of a component.
|
|||
|
|
*
|
|||
|
|
* <p>This implementation is a no-op.
|
|||
|
|
*/
|
|||
|
|
public void ready() {}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Called when the producer method is about to start executing. This will be called from the same
|
|||
|
|
* thread as the producer method itself.
|
|||
|
|
*
|
|||
|
|
* <p>When multiple monitors are installed, calls to this method will be in the reverse order from
|
|||
|
|
* calls to {@link #requested()}.
|
|||
|
|
*
|
|||
|
|
* <p>This implementation is a no-op.
|
|||
|
|
*/
|
|||
|
|
public void methodStarting() {}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Called when the producer method has finished executing. This will be called from the same
|
|||
|
|
* thread as {@link #methodStarting()} and the producer method itself.
|
|||
|
|
*
|
|||
|
|
* <p>When multiple monitors are installed, calls to this method will be in the reverse order from
|
|||
|
|
* calls to {@link #requested()}.
|
|||
|
|
*
|
|||
|
|
* <p>This implementation is a no-op.
|
|||
|
|
*/
|
|||
|
|
public void methodFinished() {}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Called when the producer’s future has completed successfully with a value.
|
|||
|
|
*
|
|||
|
|
* <p>When multiple monitors are installed, calls to this method will be in the reverse order from
|
|||
|
|
* calls to {@link #requested()}.
|
|||
|
|
*
|
|||
|
|
* <p>This implementation is a no-op.
|
|||
|
|
*/
|
|||
|
|
public void succeeded(@SuppressWarnings("unused") Object value) {}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Called when the producer's future has failed with an exception.
|
|||
|
|
*
|
|||
|
|
* <p>When multiple monitors are installed, calls to this method will be in the reverse order from
|
|||
|
|
* calls to {@link #requested()}.
|
|||
|
|
*
|
|||
|
|
* <p>This implementation is a no-op.
|
|||
|
|
*/
|
|||
|
|
public void failed(@SuppressWarnings("unused") Throwable t) {}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Adds this monitor's completion methods as a callback to the future. This is only intended to be
|
|||
|
|
* overridden in the framework!
|
|||
|
|
*/
|
|||
|
|
public <T> void addCallbackTo(ListenableFuture<T> future) {
|
|||
|
|
addCallback(
|
|||
|
|
future,
|
|||
|
|
new FutureCallback<T>() {
|
|||
|
|
@Override
|
|||
|
|
public void onSuccess(T value) {
|
|||
|
|
succeeded(value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void onFailure(Throwable t) {
|
|||
|
|
failed(t);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
directExecutor());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static final ProducerMonitor NO_OP =
|
|||
|
|
new ProducerMonitor() {
|
|||
|
|
@Override
|
|||
|
|
public <T> void addCallbackTo(ListenableFuture<T> future) {
|
|||
|
|
// overridden to avoid adding a do-nothing callback
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/** Returns a monitor that does no monitoring. */
|
|||
|
|
public static ProducerMonitor noOp() {
|
|||
|
|
return NO_OP;
|
|||
|
|
}
|
|||
|
|
}
|