View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.monitoring.jdbc;
19  
20  import org.apache.commons.monitoring.counters.Counter;
21  import org.apache.commons.monitoring.stopwatches.CounterStopWatch;
22  import org.apache.commons.monitoring.stopwatches.StopWatch;
23  import org.apache.commons.monitoring.util.ClassLoaders;
24  
25  import java.lang.reflect.InvocationHandler;
26  import java.lang.reflect.InvocationTargetException;
27  import java.lang.reflect.Method;
28  import java.lang.reflect.Proxy;
29  import java.sql.CallableStatement;
30  import java.sql.Connection;
31  import java.sql.PreparedStatement;
32  import java.sql.Statement;
33  
34  /**
35   * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
36   */
37  public class MonitoredConnection implements InvocationHandler {
38      private Connection connection;
39      private StopWatch stopWatch;
40  
41      /**
42       * @param connection target connection
43       */
44      public MonitoredConnection(final Connection connection, final StopWatch stopWatch) {
45          this.connection = connection;
46          this.stopWatch = stopWatch;
47      }
48  
49      @Override
50      public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
51          final String name = method.getName();
52          if ("close".equals(name)) {
53              connection.close();
54              stopWatch.stop();
55              return null;
56          }
57  
58          if (name.startsWith("prepare") || name.startsWith("create")) {
59              final Class<?> returnType = method.getReturnType();
60              if (CallableStatement.class.equals(returnType)) {
61                  return monitor(CallableStatement.class.cast(doInvoke(method, args)), (String) args[0]);
62              } else if (PreparedStatement.class.equals(returnType)) {
63                  return monitor(PreparedStatement.class.cast(doInvoke(method, args)), (String) args[0]);
64              } else if (Statement.class.equals(returnType)) {
65                  return monitor(Statement.class.cast(doInvoke(method, args)));
66              }
67          }
68  
69          return doInvoke(method, args);
70      }
71  
72      private Object doInvoke(final Method method, final Object[] args) throws IllegalAccessException, InvocationTargetException {
73          return method.invoke(connection, args);
74      }
75  
76      private Statement monitor(final Statement statement) {
77          return Statement.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{Statement.class}, new MonitoredStatement(statement)));
78      }
79  
80      /**
81       * @param statement traget PreparedStatement
82       * @param sql       SQL Query
83       * @return monitored PreparedStatement
84       */
85      private PreparedStatement monitor(final PreparedStatement statement, final String sql) {
86          return PreparedStatement.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{PreparedStatement.class}, new MonitoredPreparedStatement(statement, sql)));
87      }
88  
89      /**
90       * @param statement target PreparedStatement
91       * @param sql       SQL Query
92       * @return Monitored CallableStatement
93       */
94      private CallableStatement monitor(final CallableStatement statement, final String sql) {
95          return CallableStatement.class.cast(Proxy.newProxyInstance(ClassLoaders.current(), new Class<?>[]{CallableStatement.class}, new MonitoredPreparedStatement(statement, sql)));
96      }
97  
98      public static Connection monitor(final Connection connection, final Counter counter) {
99          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 }