001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.monitoring.aop;
019    
020    import org.apache.commons.monitoring.Role;
021    import org.apache.commons.monitoring.counters.Counter;
022    import org.apache.commons.monitoring.repositories.Repository;
023    import org.apache.commons.monitoring.stopwatches.StopWatch;
024    
025    import java.io.ByteArrayOutputStream;
026    import java.io.PrintStream;
027    import java.lang.reflect.Method;
028    
029    /**
030     * A method interceptor that compute method invocation performances.
031     * <p/>
032     * Concrete implementation will adapt the method interception API to
033     * this class requirement.
034     *
035     * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
036     */
037    public abstract class AbstractPerformanceInterceptor<T> {
038    
039        protected MonitorNameExtractor monitorNameExtractor;
040    
041        public AbstractPerformanceInterceptor() {
042            setMonitorNameExtractor(DefaultMonitorNameExtractor.INSTANCE);
043        }
044    
045        /**
046         * API neutral method invocation
047         */
048        protected Object doInvoke(final T invocation) throws Throwable {
049            final String name = getCounterName(invocation);
050            if (name == null) {
051                return proceed(invocation);
052            }
053    
054            final Counter monitor = Repository.INSTANCE.getCounter(new Counter.Key(Role.PERFORMANCES, name));
055            final StopWatch stopwatch = Repository.INSTANCE.start(monitor);
056            Throwable error = null;
057            try {
058                return proceed(invocation);
059            } catch (final Throwable t) {
060                error = t;
061                throw t;
062            } finally {
063                stopwatch.stop();
064                if (error != null) {
065                    final ByteArrayOutputStream writer = new ByteArrayOutputStream();
066                    error.printStackTrace(new PrintStream(writer));
067                    Repository.INSTANCE.getCounter(new Counter.Key(Role.FAILURES, writer.toString())).add(stopwatch.getElapsedTime());
068                }
069            }
070        }
071    
072        protected abstract Object proceed(T invocation) throws Throwable;
073    
074        protected abstract String getCounterName(T invocation);
075    
076        /**
077         * Compute the counter name associated to this method invocation
078         *
079         * @param method method being invoked
080         * @return counter name. If <code>null</code>, nothing will be monitored
081         */
082        protected String getCounterName(final Object instance, final Method method) {
083            return monitorNameExtractor.getMonitorName(instance, method);
084        }
085    
086        public void setMonitorNameExtractor(final MonitorNameExtractor monitorNameExtractor) {
087            this.monitorNameExtractor = monitorNameExtractor;
088        }
089    }