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.counters.Counter;
021 import org.apache.commons.monitoring.stopwatches.CounterStopWatch;
022 import org.apache.commons.monitoring.stopwatches.StopWatch;
023 import org.apache.commons.monitoring.util.ClassLoaders;
024
025 import java.lang.reflect.InvocationHandler;
026 import java.lang.reflect.InvocationTargetException;
027 import java.lang.reflect.Method;
028 import java.lang.reflect.Proxy;
029 import java.sql.CallableStatement;
030 import java.sql.Connection;
031 import java.sql.PreparedStatement;
032 import java.sql.Statement;
033
034 /**
035 * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
036 */
037 public class MonitoredConnection implements InvocationHandler {
038 private Connection connection;
039 private StopWatch stopWatch;
040
041 /**
042 * @param connection target connection
043 */
044 public MonitoredConnection(final Connection connection, final StopWatch stopWatch) {
045 this.connection = connection;
046 this.stopWatch = stopWatch;
047 }
048
049 @Override
050 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
051 final String name = method.getName();
052 if ("close".equals(name)) {
053 connection.close();
054 stopWatch.stop();
055 return null;
056 }
057
058 if (name.startsWith("prepare") || name.startsWith("create")) {
059 final Class<?> returnType = method.getReturnType();
060 if (CallableStatement.class.equals(returnType)) {
061 return monitor(CallableStatement.class.cast(doInvoke(method, args)), (String) args[0]);
062 } else if (PreparedStatement.class.equals(returnType)) {
063 return monitor(PreparedStatement.class.cast(doInvoke(method, args)), (String) args[0]);
064 } else if (Statement.class.equals(returnType)) {
065 return monitor(Statement.class.cast(doInvoke(method, args)));
066 }
067 }
068
069 return doInvoke(method, args);
070 }
071
072 private Object doInvoke(final Method method, final Object[] args) throws IllegalAccessException, InvocationTargetException {
073 return method.invoke(connection, args);
074 }
075
076 private Statement monitor(final Statement statement) {
077 return Statement.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{Statement.class}, new MonitoredStatement(statement)));
078 }
079
080 /**
081 * @param statement traget PreparedStatement
082 * @param sql SQL Query
083 * @return monitored PreparedStatement
084 */
085 private PreparedStatement monitor(final PreparedStatement statement, final String sql) {
086 return PreparedStatement.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{PreparedStatement.class}, new MonitoredPreparedStatement(statement, sql)));
087 }
088
089 /**
090 * @param statement target PreparedStatement
091 * @param sql SQL Query
092 * @return Monitored CallableStatement
093 */
094 private CallableStatement monitor(final CallableStatement statement, final String sql) {
095 return CallableStatement.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{CallableStatement.class}, new MonitoredPreparedStatement(statement, sql)));
096 }
097
098 public static Connection monitor(final Connection connection, final Counter counter) {
099 final StopWatch stopWatch = new CounterStopWatch(counter);
100 return Connection.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{Connection.class}, new MonitoredConnection(connection, stopWatch)));
101 }
102 }