All Downloads are FREE. Search and download functionalities are using the official Maven repository.

patterntesting.runtime.monitor.db.ProxyConnection Maven / Gradle / Ivy

Go to download

PatternTesting Runtime (patterntesting-rt) is the runtime component for the PatternTesting framework. It provides the annotations and base classes for the PatternTesting testing framework (e.g. patterntesting-check, patterntesting-concurrent or patterntesting-exception) but can be also used standalone for classpath monitoring or profiling. It uses AOP and AspectJ to perform this feat.

There is a newer version: 2.4.0
Show newest version
/*
 * $Id: ProxyConnection.java,v 1.2 2014/04/27 19:35:07 oboehm Exp $
 *
 * Copyright (c) 2012-2014 by Oliver Boehm
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * (c)reated 29.09.2012 by oliver ([email protected])
 */

package patterntesting.runtime.monitor.db;

import java.lang.reflect.*;
import java.sql.*;

import org.slf4j.*;

import patterntesting.runtime.annotation.IgnoreForSequenceDiagram;
import patterntesting.runtime.monitor.db.internal.*;
import patterntesting.runtime.util.Converter;

/**
 * This is a dynamic proxy for a JDBC connection which monitors together with
 * the {@link ConnectionMonitor} the different newInstance() and close() call.
 * 

* Note: Since 1.4.2 this class was moved from package * "patterntesting.runtime.db" to here. *

* * @author oliver ([email protected]) * @since 1.3 (29.09.2012) * @version $Revision: 1.2 $ */ @IgnoreForSequenceDiagram public class ProxyConnection implements InvocationHandler { private static final Logger log = LoggerFactory.getLogger(ProxyConnection.class); private final Connection connection; private final StackTraceElement[] caller; /** * Creates a new proxy instance for the given connection. * * @param connection the connection * @return the connection */ public static Connection newInstance(final Connection connection) { ProxyConnection proxyConnection = new ProxyConnection(connection); ConnectionMonitor.addConnection(proxyConnection); Class[] interfaces = new Class[] { Connection.class }; return (Connection) Proxy.newProxyInstance(connection.getClass().getClassLoader(), interfaces, proxyConnection); } /** * Instantiates a new proxy connection. This constructor is called from * {@link #newInstance(Connection)} which is of no interest for us. We want * to store the real caller so we ignore the {@link ProxyConnection} class * but also the {@link ProxyDriver} class (ProxyDriver also calls this * constructor indirectly) and other non-interesting classes. * * @param connection the connection */ protected ProxyConnection(final Connection connection) { this.connection = connection; this.caller = getCallerStacktrace(ProxyConnection.class, ProxyDriver.class, ConnectionMonitor.class, DriverManager.class); } /** * Gets the caller stacktrace. To find the real caller we ignore the first * 3 elements from the stacktrace because this is e.g. the method * {@link Thread#getStackTrace()} which is not relevant here. * * @param ignoredClasses the ignored classes * @return the caller stacktrace */ private static StackTraceElement[] getCallerStacktrace(final Class... ignoredClasses) { StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace(); for (int i = 3; i < stacktrace.length; i++) { if (!matches(stacktrace[i].getClassName(), ignoredClasses)) { StackTraceElement[] stacktraceCaller = new StackTraceElement[stacktrace.length - i]; System.arraycopy(stacktrace, i, stacktraceCaller, 0, stacktrace.length - i); return stacktraceCaller; } } throw new IllegalStateException("no caller found for " + Converter.toString(ignoredClasses)); } private static boolean matches(final String classname, final Class...classes) { for (int i = 0; i < classes.length; i++) { if (classname.equals(classes[i].getName())) { return true; } } return false; } /** * Invokes the orginal {@link Connection} method and puts a wrapper around * {@link Statement} and {@link PreparedStatement} to support monitoring. *

* TODO: CallableStatement is not yet wrapped. *

* * @param proxy the proxy * @param method the method * @param args the args * @return the object * @throws Throwable the throwable * @see java.lang.reflect.InvocationHandler#invoke(Object, Method, Object[]) */ public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { assert method != null; String methodName = method.getName(); try { if (methodName.equals("close")) { ConnectionMonitor.removeConnection(this); } else if (methodName.equals("createStatement")) { Statement stmt = (Statement) method.invoke(connection, args); return new StasiStatement(stmt); } else if (methodName.equals("prepareStatement")) { PreparedStatement stmt = (PreparedStatement) method.invoke(connection, args); return new StasiPreparedStatement(stmt, args); } else if (methodName.equals("toString")) { return this.toString(); } return method.invoke(connection, args); } catch (InvocationTargetException ite) { log.debug("Cannot invoke {} ({})!", method, ite); throw ite.getTargetException(); } } /** * Gets the wrapped connection. * * @return the connection */ public Connection getConnection() { return this.connection; } /** * Gets the stacktrace of the caller. * * @return the caller stacktrace */ public StackTraceElement[] getCaller() { return this.caller; } /** * To string. * * @return the string * @see java.lang.Object#toString() */ @Override public String toString() { return this.getClass().getSimpleName() + " for " + this.caller[0]; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy