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.jdbc;
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.lang.reflect.InvocationHandler;
026    import java.lang.reflect.InvocationTargetException;
027    import java.lang.reflect.Method;
028    import java.sql.SQLException;
029    import java.sql.Statement;
030    
031    public class MonitoredStatement implements InvocationHandler {
032        private final Statement statement;
033    
034        public MonitoredStatement(final Statement statement) {
035            this.statement = statement;
036        }
037    
038        protected SQLException monitor(final SQLException sqle) {
039            final String name = "SQLException:" + sqle.getSQLState() + ":" + sqle.getErrorCode();
040            Repository.INSTANCE.getCounter(new Counter.Key(Role.FAILURES, name)).add(1);
041            return sqle;
042        }
043    
044        @Override
045        public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
046            final String name = method.getName();
047            if (name.startsWith("execute")) {
048                final StopWatch stopWatch;
049                if (name.endsWith("Batch") && (args == null || args.length == 0)) {
050                    stopWatch = Repository.INSTANCE.start(Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, "batch")));
051                } else {
052                    stopWatch = Repository.INSTANCE.start(Repository.INSTANCE.getCounter(new Counter.Key(Role.JDBC, (String) args[0])));
053                }
054    
055                try {
056                    return doInvoke(method, args);
057                } catch (final InvocationTargetException e) {
058                    throw extractSQLException(e);
059                } finally {
060                    stopWatch.stop();
061                }
062            }
063            return doInvoke(method, args);
064        }
065    
066        private Object doInvoke(final Method method, final Object[] args) throws IllegalAccessException, InvocationTargetException {
067            return method.invoke(statement, args);
068        }
069    
070        protected Throwable extractSQLException(final InvocationTargetException e) throws Throwable {
071            final Throwable th = e.getCause();
072            if (SQLException.class.isInstance(th)) {
073                return monitor(SQLException.class.cast(th));
074            }
075            return th;
076        }
077    }