dagger.producers.monitoring.TimingRecorders.java Source code

Java tutorial

Introduction

Here is the source code for dagger.producers.monitoring.TimingRecorders.java

Source

/*
 * 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 com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import dagger.internal.Beta;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Utility methods relating to timing.
 *
 * @author Jesse Beder
 */
// TODO(beder): Reduce the visibility of this class to package-private.
@Beta
public final class TimingRecorders {
    private static final Logger logger = Logger.getLogger(TimingRecorders.class.getName());

    /**
     * Returns a timing recorder factory that delegates to the given factories, and ensures that any
     * method called on this object, even transitively, does not throw a {@link RuntimeException} or
     * return null.
     *
     * <p>If the delegate recorders throw an {@link Error}, then that will escape this recorder
     * implementation. Errors are treated as unrecoverable conditions, and may cause the entire
     * component's execution to fail.
     */
    public static ProductionComponentTimingRecorder.Factory delegatingProductionComponentTimingRecorderFactory(
            Collection<ProductionComponentTimingRecorder.Factory> factories) {
        switch (factories.size()) {
        case 0:
            return noOpProductionComponentTimingRecorderFactory();
        case 1:
            return new NonThrowingProductionComponentTimingRecorder.Factory(Iterables.getOnlyElement(factories));
        default:
            return new DelegatingProductionComponentTimingRecorder.Factory(factories);
        }
    }

    /**
     * A component recorder that delegates to a single recorder, and catches and logs all exceptions
     * that the delegate throws.
     */
    private static final class NonThrowingProductionComponentTimingRecorder
            implements ProductionComponentTimingRecorder {
        private final ProductionComponentTimingRecorder delegate;

        NonThrowingProductionComponentTimingRecorder(ProductionComponentTimingRecorder delegate) {
            this.delegate = delegate;
        }

        @Override
        public ProducerTimingRecorder producerTimingRecorderFor(ProducerToken token) {
            try {
                ProducerTimingRecorder recorder = delegate.producerTimingRecorderFor(token);
                return recorder == null ? ProducerTimingRecorder.noOp()
                        : new NonThrowingProducerTimingRecorder(recorder);
            } catch (RuntimeException e) {
                logProducerTimingRecorderForException(e, delegate, token);
                return ProducerTimingRecorder.noOp();
            }
        }

        static final class Factory implements ProductionComponentTimingRecorder.Factory {
            private final ProductionComponentTimingRecorder.Factory delegate;

            Factory(ProductionComponentTimingRecorder.Factory delegate) {
                this.delegate = delegate;
            }

            @Override
            public ProductionComponentTimingRecorder create(Object component) {
                try {
                    ProductionComponentTimingRecorder recorder = delegate.create(component);
                    return recorder == null ? noOpProductionComponentTimingRecorder()
                            : new NonThrowingProductionComponentTimingRecorder(recorder);
                } catch (RuntimeException e) {
                    logCreateException(e, delegate, component);
                    return noOpProductionComponentTimingRecorder();
                }
            }
        }
    }

    /**
     * A producer recorder that delegates to a single recorder, and catches and logs all exceptions
     * that the delegate throws.
     */
    private static final class NonThrowingProducerTimingRecorder extends ProducerTimingRecorder {
        private final ProducerTimingRecorder delegate;

        NonThrowingProducerTimingRecorder(ProducerTimingRecorder delegate) {
            this.delegate = delegate;
        }

        @Override
        public void recordMethod(long startedNanos, long durationNanos) {
            try {
                delegate.recordMethod(startedNanos, durationNanos);
            } catch (RuntimeException e) {
                logProducerTimingRecorderMethodException(e, delegate, "recordMethod");
            }
        }

        @Override
        public void recordSuccess(long latencyNanos) {
            try {
                delegate.recordSuccess(latencyNanos);
            } catch (RuntimeException e) {
                logProducerTimingRecorderMethodException(e, delegate, "recordSuccess");
            }
        }

        @Override
        public void recordFailure(Throwable exception, long latencyNanos) {
            try {
                delegate.recordFailure(exception, latencyNanos);
            } catch (RuntimeException e) {
                logProducerTimingRecorderMethodException(e, delegate, "recordFailure");
            }
        }

        @Override
        public void recordSkip(Throwable exception) {
            try {
                delegate.recordSkip(exception);
            } catch (RuntimeException e) {
                logProducerTimingRecorderMethodException(e, delegate, "recordSkip");
            }
        }
    }

    /**
     * A component recorder that delegates to several recorders, and catches and logs all exceptions
     * that the delegates throw.
     */
    private static final class DelegatingProductionComponentTimingRecorder
            implements ProductionComponentTimingRecorder {
        private final ImmutableList<ProductionComponentTimingRecorder> delegates;

        DelegatingProductionComponentTimingRecorder(ImmutableList<ProductionComponentTimingRecorder> delegates) {
            this.delegates = delegates;
        }

        @Override
        public ProducerTimingRecorder producerTimingRecorderFor(ProducerToken token) {
            ImmutableList.Builder<ProducerTimingRecorder> recordersBuilder = ImmutableList.builder();
            for (ProductionComponentTimingRecorder delegate : delegates) {
                try {
                    ProducerTimingRecorder recorder = delegate.producerTimingRecorderFor(token);
                    if (recorder != null) {
                        recordersBuilder.add(recorder);
                    }
                } catch (RuntimeException e) {
                    logProducerTimingRecorderForException(e, delegate, token);
                }
            }
            ImmutableList<ProducerTimingRecorder> recorders = recordersBuilder.build();
            switch (recorders.size()) {
            case 0:
                return ProducerTimingRecorder.noOp();
            case 1:
                return new NonThrowingProducerTimingRecorder(Iterables.getOnlyElement(recorders));
            default:
                return new DelegatingProducerTimingRecorder(recorders);
            }
        }

        static final class Factory implements ProductionComponentTimingRecorder.Factory {
            private final ImmutableList<? extends ProductionComponentTimingRecorder.Factory> delegates;

            Factory(Iterable<? extends ProductionComponentTimingRecorder.Factory> delegates) {
                this.delegates = ImmutableList.copyOf(delegates);
            }

            @Override
            public ProductionComponentTimingRecorder create(Object component) {
                ImmutableList.Builder<ProductionComponentTimingRecorder> recordersBuilder = ImmutableList.builder();
                for (ProductionComponentTimingRecorder.Factory delegate : delegates) {
                    try {
                        ProductionComponentTimingRecorder recorder = delegate.create(component);
                        if (recorder != null) {
                            recordersBuilder.add(recorder);
                        }
                    } catch (RuntimeException e) {
                        logCreateException(e, delegate, component);
                    }
                }
                ImmutableList<ProductionComponentTimingRecorder> recorders = recordersBuilder.build();
                switch (recorders.size()) {
                case 0:
                    return noOpProductionComponentTimingRecorder();
                case 1:
                    return new NonThrowingProductionComponentTimingRecorder(Iterables.getOnlyElement(recorders));
                default:
                    return new DelegatingProductionComponentTimingRecorder(recorders);
                }
            }
        }
    }

    /**
     * A producer recorder that delegates to several recorders, and catches and logs all exceptions
     * that the delegates throw.
     */
    private static final class DelegatingProducerTimingRecorder extends ProducerTimingRecorder {
        private final ImmutableList<ProducerTimingRecorder> delegates;

        DelegatingProducerTimingRecorder(ImmutableList<ProducerTimingRecorder> delegates) {
            this.delegates = delegates;
        }

        @Override
        public void recordMethod(long startedNanos, long durationNanos) {
            for (ProducerTimingRecorder delegate : delegates) {
                try {
                    delegate.recordMethod(startedNanos, durationNanos);
                } catch (RuntimeException e) {
                    logProducerTimingRecorderMethodException(e, delegate, "recordMethod");
                }
            }
        }

        @Override
        public void recordSuccess(long latencyNanos) {
            for (ProducerTimingRecorder delegate : delegates) {
                try {
                    delegate.recordSuccess(latencyNanos);
                } catch (RuntimeException e) {
                    logProducerTimingRecorderMethodException(e, delegate, "recordSuccess");
                }
            }
        }

        @Override
        public void recordFailure(Throwable exception, long latencyNanos) {
            for (ProducerTimingRecorder delegate : delegates) {
                try {
                    delegate.recordFailure(exception, latencyNanos);
                } catch (RuntimeException e) {
                    logProducerTimingRecorderMethodException(e, delegate, "recordFailure");
                }
            }
        }

        @Override
        public void recordSkip(Throwable exception) {
            for (ProducerTimingRecorder delegate : delegates) {
                try {
                    delegate.recordSkip(exception);
                } catch (RuntimeException e) {
                    logProducerTimingRecorderMethodException(e, delegate, "recordSkip");
                }
            }
        }
    }

    /** Returns a recorder factory that returns no-op component recorders. */
    public static ProductionComponentTimingRecorder.Factory noOpProductionComponentTimingRecorderFactory() {
        return NO_OP_PRODUCTION_COMPONENT_TIMING_RECORDER_FACTORY;
    }

    /** Returns a component recorder that returns no-op producer recorders. */
    public static ProductionComponentTimingRecorder noOpProductionComponentTimingRecorder() {
        return NO_OP_PRODUCTION_COMPONENT_TIMING_RECORDER;
    }

    private static final ProductionComponentTimingRecorder.Factory NO_OP_PRODUCTION_COMPONENT_TIMING_RECORDER_FACTORY = new ProductionComponentTimingRecorder.Factory() {
        @Override
        public ProductionComponentTimingRecorder create(Object component) {
            return noOpProductionComponentTimingRecorder();
        }
    };

    private static final ProductionComponentTimingRecorder NO_OP_PRODUCTION_COMPONENT_TIMING_RECORDER = new ProductionComponentTimingRecorder() {
        @Override
        public ProducerTimingRecorder producerTimingRecorderFor(ProducerToken token) {
            return ProducerTimingRecorder.noOp();
        }
    };

    private static void logCreateException(RuntimeException e, ProductionComponentTimingRecorder.Factory factory,
            Object component) {
        logger.log(Level.SEVERE,
                "RuntimeException while calling ProductionComponentTimingRecorder.Factory.create on" + " factory "
                        + factory + " with component " + component,
                e);
    }

    private static void logProducerTimingRecorderForException(RuntimeException e,
            ProductionComponentTimingRecorder recorder, ProducerToken token) {
        logger.log(Level.SEVERE,
                "RuntimeException while calling ProductionComponentTimingRecorder.producerTimingRecorderFor"
                        + "on recorder " + recorder + " with token " + token,
                e);
    }

    private static void logProducerTimingRecorderMethodException(RuntimeException e,
            ProducerTimingRecorder recorder, String method) {
        logger.log(Level.SEVERE,
                "RuntimeException while calling ProducerTimingRecorder." + method + " on recorder " + recorder, e);
    }

    private TimingRecorders() {
    }
}