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 }