Refactor to allow injection of proxy code into JDBC classes from the user's driver.

pull/1/head
Brett Wooldridge 11 years ago
parent 0b58689069
commit 1f013c3f09

@ -36,7 +36,7 @@ import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.proxy.HikariInstrumentationAgent;
import com.zaxxer.hikari.javassist.HikariInstrumentationAgent;
import com.zaxxer.hikari.proxy.IHikariConnectionProxy;
import com.zaxxer.hikari.proxy.JavassistProxyFactoryFactory;
import com.zaxxer.hikari.util.ClassLoaderUtils;
@ -82,7 +82,7 @@ public class HikariPool implements HikariPoolMBean
PropertyBeanSetter.setTargetFromProperties(dataSource, configuration.getDataSourceProperties());
HikariInstrumentationAgent instrumentationAgent = new HikariInstrumentationAgent(dataSource);
if (true || !instrumentationAgent.loadTransformerAgent())
if (false || !instrumentationAgent.loadTransformerAgent())
{
delegationProxies = true;
LOGGER.info("Falling back to Javassist delegate-based proxies.");
@ -261,6 +261,7 @@ public class HikariPool implements HikariPoolMBean
else
{
proxyConnection = (IHikariConnectionProxy) connection;
proxyConnection.setParentPool(this);
}
boolean alive = isConnectionAlive((Connection) proxyConnection, configuration.getConnectionTimeout());
@ -329,7 +330,7 @@ public class HikariPool implements HikariPoolMBean
try
{
totalConnections.decrementAndGet();
connectionProxy.getDelegate().close();
connectionProxy.__close();
}
catch (SQLException e)
{

@ -17,87 +17,21 @@
package com.zaxxer.hikari.proxy;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
*
* @author Brett Wooldridge
*/
public class CallableStatementProxy extends HikariProxyBase
public class CallableStatementProxy extends PreparedStatementProxy
{
private static final ProxyFactory PROXY_FACTORY;
private final ConnectionProxy connection;
protected final CallableStatement delegate;
static
{
PROXY_FACTORY = JavassistProxyFactoryFactory.getProxyFactory();
}
protected CallableStatementProxy(ConnectionProxy connection, CallableStatement statement)
{
this.connection = connection;
this.delegate = statement;
}
protected SQLException checkException(SQLException e)
{
return connection.checkException(e);
super(connection, statement);
}
// **********************************************************************
// Overridden java.sql.CallableStatement Methods
// other methods are injected
// **********************************************************************
public void close() throws SQLException
{
if (delegate == null)
{
return;
}
connection.unregisterStatement(delegate);
delegate.close();
}
public ResultSet executeQuery() throws SQLException
{
return PROXY_FACTORY.getProxyResultSet((CallableStatement) this, delegate.executeQuery());
}
public ResultSet executeQuery(String sql) throws SQLException
{
return PROXY_FACTORY.getProxyResultSet((CallableStatement) this, delegate.executeQuery(sql));
}
public ResultSet getGeneratedKeys() throws SQLException
{
return PROXY_FACTORY.getProxyResultSet((CallableStatement) this, delegate.getGeneratedKeys());
}
/* java.sql.Wrapper implementation */
// TODO implement wrapper
// public boolean isWrapperFor(Class<?> iface) throws SQLException
// {
// return iface.isAssignableFrom(delegate.getClass()) || isWrapperFor(delegate, iface);
// }
//
// @SuppressWarnings("unchecked")
// public <T> T unwrap(Class<T> iface) throws SQLException
// {
// if (iface.isAssignableFrom(delegate.getClass()))
// {
// return (T) delegate;
// }
// if (isWrapperFor(iface))
// {
// return unwrap(delegate, iface);
// }
// throw new SQLException(getClass().getName() + " is not a wrapper for " + iface);
// }
}

@ -28,36 +28,44 @@ import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.HikariPool;
import com.zaxxer.hikari.javassist.HikariInject;
/**
* This is the proxy class for java.sql.Connection. It is used in
* two ways:
*
* 1) If instrumentation is not used, Javassist will generate a new class
* that extends this class and delegates all method calls to the 'delegate'
* member (which points to the real Connection).
*
* 2) If instrumentation IS used, Javassist will be used to inject all of
* the non-final methods of this class into the actual Connection implementation
* provided by the JDBC driver. All of the fields, <i>except</i> for PROXY_FACTORY
* and 'delegate' are also injected. In order to avoid name conflicts the
* fields of this class have slightly unconventional names.
*
* @author Brett Wooldridge
*/
public class ConnectionProxy extends HikariProxyBase implements IHikariConnectionProxy
{
private static final ProxyFactory PROXY_FACTORY;
private static ProxyFactory PROXY_FACTORY;
private static final Set<String> POSTGRESQL_ERRORS;
private static final Set<String> SPECIAL_ERRORS;
@HikariInject private static final Set<String> POSTGRESQL_ERRORS;
@HikariInject private static final Set<String> SPECIAL_ERRORS;
private final ArrayList<Statement> openStatements;
private final AtomicBoolean isClosed;
private final HikariPool parentPool;
@HikariInject private ArrayList<IHikariStatementProxy> _openStatements;
@HikariInject private AtomicBoolean _isClosed;
@HikariInject private HikariPool _parentPool;
protected final Connection delegate;
private volatile boolean forceClose;
private final long creationTime;
private long lastAccess;
private StackTraceElement[] stackTrace;
@HikariInject private volatile boolean _forceClose;
@HikariInject private long _creationTime;
@HikariInject private long _lastAccess;
private TimerTask leakTask;
@HikariInject private StackTraceElement[] _stackTrace;
@HikariInject private TimerTask _leakTask;
// static initializer
static
@ -71,88 +79,90 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
SPECIAL_ERRORS = new HashSet<String>();
SPECIAL_ERRORS.add("01002"); // SQL92 disconnect error
PROXY_FACTORY = JavassistProxyFactoryFactory.getProxyFactory();
__static();
}
// Instance initializer
@HikariInject
private void __init()
{
openStatements = new ArrayList<Statement>(64);
isClosed = new AtomicBoolean();
creationTime = lastAccess = System.currentTimeMillis();
_openStatements = new ArrayList<IHikariStatementProxy>(64);
_isClosed = new AtomicBoolean();
_creationTime = _lastAccess = System.currentTimeMillis();
}
protected ConnectionProxy(HikariPool parentPool, Connection connection)
{
this.parentPool = parentPool;
this._parentPool = parentPool;
this.delegate = connection;
__init();
}
void unregisterStatement(Object statement)
@HikariInject
public void unregisterStatement(Object statement)
{
// If the connection is not closed. If it is closed, it means this is being
// called back as a result of the close() method below in which case we
// will clear the openStatements collection en mass.
if (!isClosed.get())
if (!_isClosed.get())
{
openStatements.remove(statement);
_openStatements.remove(statement);
}
}
@HikariInject
public long getCreationTime()
{
return creationTime;
return _creationTime;
}
@HikariInject
public long getLastAccess()
{
return lastAccess;
return _lastAccess;
}
@HikariInject
public void setLastAccess(long timestamp)
{
this.lastAccess = timestamp;
this._lastAccess = timestamp;
}
@HikariInject
public void setParentPool(HikariPool parentPool)
{
this._parentPool = parentPool;
}
@HikariInject
public void unclose()
{
isClosed.set(false);
_isClosed.set(false);
}
public Connection getDelegate()
public final Connection getDelegate()
{
return delegate;
}
@HikariInject
public void captureStack(long leakDetectionThreshold, Timer scheduler)
{
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
stackTrace = new StackTraceElement[trace.length - 4];
System.arraycopy(trace, 4, stackTrace, 0, stackTrace.length);
_stackTrace = new StackTraceElement[trace.length - 4];
System.arraycopy(trace, 4, _stackTrace, 0, _stackTrace.length);
final long leakTime = System.currentTimeMillis() + leakDetectionThreshold;
leakTask = new TimerTask()
{
public void run()
{
if (System.currentTimeMillis() > leakTime)
{
Exception e = new Exception();
e.setStackTrace(stackTrace);
LoggerFactory.getLogger(ConnectionProxy.this.getClass()).warn("Connection leak detection triggered, stack trace follows", e);
stackTrace = null;
}
}
};
scheduler.schedule(leakTask, leakDetectionThreshold);
_leakTask = new LeakTask(_stackTrace, leakDetectionThreshold);
scheduler.schedule(_leakTask, leakDetectionThreshold);
}
@HikariInject
public boolean isBrokenConnection()
{
return forceClose;
return _forceClose;
}
protected SQLException checkException(SQLException sqle)
@HikariInject
public SQLException checkException(SQLException sqle)
{
String sqlState = sqle.getSQLState();
if (sqlState == null)
@ -163,42 +173,39 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
sqlState = sqlState.toUpperCase();
if (sqlState.startsWith("08"))
{
forceClose = true;
_forceClose = true;
}
else if (POSTGRESQL_ERRORS.contains(sqlState.toUpperCase()) || SPECIAL_ERRORS.contains(sqlState))
{
forceClose = true;
_forceClose = true;
}
return sqle;
}
// **********************************************************************
// Overridden java.sql.Connection Methods
// other methods are injected
// "Overridden" java.sql.Connection Methods
// **********************************************************************
/* (non-Javadoc)
* @see java.sql.Connection#close()
*/
@HikariInject
public void close() throws SQLException
{
if (isClosed.compareAndSet(false, true))
if (_isClosed.compareAndSet(false, true))
{
if (leakTask != null)
if (_leakTask != null)
{
leakTask.cancel();
leakTask = null;
_leakTask.cancel();
_leakTask = null;
}
if (delegate.getAutoCommit())
if (getAutoCommit())
{
delegate.commit();
commit();
}
try
{
for (Statement statement : openStatements)
for (IHikariStatementProxy statement : _openStatements)
{
statement.close();
}
@ -209,31 +216,28 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
finally
{
openStatements.clear();
parentPool.releaseConnection(this);
_openStatements.clear();
_parentPool.releaseConnection(this);
}
}
}
/* (non-Javadoc)
* @see java.sql.Connection#isClosed()
*/
@HikariInject
public boolean isClosed() throws SQLException
{
return isClosed.get();
return _isClosed.get();
}
/* (non-Javadoc)
* @see java.sql.Connection#createStatement()
*/
@HikariInject
public Statement createStatement() throws SQLException
{
try
{
Statement statementProxy = PROXY_FACTORY.getProxyStatement(this, delegate.createStatement());
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __createStatement();
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (Statement) statementProxy;
}
catch (SQLException e)
{
@ -241,17 +245,16 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#createStatement(int, int)
*/
@HikariInject
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
try
{
Statement statementProxy = PROXY_FACTORY.getProxyStatement(this, delegate.createStatement(resultSetType, resultSetConcurrency));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __createStatement(resultSetType, resultSetConcurrency);
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (Statement) statementProxy;
}
catch (SQLException e)
{
@ -259,17 +262,16 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#createStatement(int, int, int)
*/
@HikariInject
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
try
{
Statement statementProxy = PROXY_FACTORY.getProxyStatement(this, delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (Statement) statementProxy;
}
catch (SQLException e)
{
@ -277,17 +279,16 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#prepareCall(java.lang.String)
*/
@HikariInject
public CallableStatement prepareCall(String sql) throws SQLException
{
try
{
CallableStatement statementProxy = PROXY_FACTORY.getProxyCallableStatement(this, delegate.prepareCall(sql));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __prepareCall(sql);
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (CallableStatement) statementProxy;
}
catch (SQLException e)
{
@ -295,17 +296,16 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#prepareCall(java.lang.String, int, int)
*/
@HikariInject
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
try
{
CallableStatement statementProxy = PROXY_FACTORY.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, resultSetConcurrency));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __prepareCall(sql, resultSetType, resultSetConcurrency);
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (CallableStatement) statementProxy;
}
catch (SQLException e)
{
@ -313,17 +313,16 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#prepareCall(java.lang.String, int, int, int)
*/
@HikariInject
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
try
{
CallableStatement statementProxy = PROXY_FACTORY.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (CallableStatement) statementProxy;
}
catch (SQLException e)
{
@ -331,17 +330,16 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#prepareStatement(java.lang.String)
*/
@HikariInject
public PreparedStatement prepareStatement(String sql) throws SQLException
{
try
{
PreparedStatement statementProxy = PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __prepareStatement(sql);
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (PreparedStatement) statementProxy;
}
catch (SQLException e)
{
@ -349,17 +347,16 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#prepareStatement(java.lang.String, int)
*/
@HikariInject
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException
{
try
{
PreparedStatement statementProxy = PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, autoGeneratedKeys));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __prepareStatement(sql, autoGeneratedKeys);
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (PreparedStatement) statementProxy;
}
catch (SQLException e)
{
@ -367,17 +364,16 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#prepareStatement(java.lang.String, int, int)
*/
@HikariInject
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
try
{
PreparedStatement statementProxy = PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, resultSetConcurrency));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __prepareStatement(sql, resultSetType, resultSetConcurrency);
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (PreparedStatement) statementProxy;
}
catch (SQLException e)
{
@ -385,17 +381,15 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#prepareStatement(java.lang.String, int, int, int)
*/
@HikariInject
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
try
{
PreparedStatement statementProxy = PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
_openStatements.add(statementProxy);
return statementProxy;
return (PreparedStatement) statementProxy;
}
catch (SQLException e)
{
@ -403,17 +397,16 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#prepareStatement(java.lang.String, int[])
*/
@HikariInject
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException
{
try
{
PreparedStatement statementProxy = PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnIndexes));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __prepareStatement(sql, columnIndexes);
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (PreparedStatement) statementProxy;
}
catch (SQLException e)
{
@ -421,21 +414,110 @@ public class ConnectionProxy extends HikariProxyBase implements IHikariConnectio
}
}
/* (non-Javadoc)
* @see java.sql.Connection#prepareStatement(java.lang.String, java.lang.String[])
*/
@HikariInject
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException
{
try
{
PreparedStatement statementProxy = PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames));
openStatements.add(statementProxy);
IHikariStatementProxy statementProxy = (IHikariStatementProxy) __prepareStatement(sql, columnNames);
statementProxy.setConnectionProxy((Connection) this);
_openStatements.add(statementProxy);
return statementProxy;
return (PreparedStatement) statementProxy;
}
catch (SQLException e)
{
throw checkException(e);
}
}
public boolean getAutoCommit() throws SQLException
{
return delegate.getAutoCommit();
}
public void commit() throws SQLException
{
delegate.commit();
}
// ***********************************************************************
// These methods contain code we do not want injected into the actual
// java.sql.Connection implementation class. These methods are only
// used when instrumentation is not available and "conventional" Javassist
// delegating proxies are used.
// ***********************************************************************
private static void __static()
{
if (PROXY_FACTORY == null)
{
PROXY_FACTORY = JavassistProxyFactoryFactory.getProxyFactory();
}
}
public final void __close() throws SQLException
{
delegate.close();
}
public final Statement __createStatement() throws SQLException
{
return PROXY_FACTORY.getProxyStatement(this, delegate.createStatement());
}
public final Statement __createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
return PROXY_FACTORY.getProxyStatement(this, delegate.createStatement(resultSetType, resultSetConcurrency));
}
public final Statement __createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
return PROXY_FACTORY.getProxyStatement(this, delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
}
public final CallableStatement __prepareCall(String sql) throws SQLException
{
return PROXY_FACTORY.getProxyCallableStatement(this, delegate.prepareCall(sql));
}
public final CallableStatement __prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
return PROXY_FACTORY.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, resultSetConcurrency));
}
public final CallableStatement __prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
return PROXY_FACTORY.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
}
public final PreparedStatement __prepareStatement(String sql) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql));
}
public final PreparedStatement __prepareStatement(String sql, int autoGeneratedKeys) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, autoGeneratedKeys));
}
public final PreparedStatement __prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, resultSetConcurrency));
}
public final PreparedStatement __prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
}
public final PreparedStatement __prepareStatement(String sql, int[] columnIndexes) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnIndexes));
}
public final PreparedStatement __prepareStatement(String sql, String[] columnNames) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames));
}
}

@ -17,8 +17,11 @@
package com.zaxxer.hikari.proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Timer;
import com.zaxxer.hikari.HikariPool;
/**
*
* @author Brett Wooldridge
@ -27,6 +30,12 @@ public interface IHikariConnectionProxy
{
void unclose();
void __close() throws SQLException;
void unregisterStatement(Object statement);
SQLException checkException(SQLException sqle);
boolean isBrokenConnection();
long getCreationTime();
@ -35,6 +44,8 @@ public interface IHikariConnectionProxy
void setLastAccess(long timestamp);
void setParentPool(HikariPool parentPool);
Connection getDelegate();
/* Leak Detection API */

@ -0,0 +1,6 @@
package com.zaxxer.hikari.proxy;
public interface IHikariResultSetProxy
{
void setProxyStatement(IHikariStatementProxy proxy);
}

@ -0,0 +1,13 @@
package com.zaxxer.hikari.proxy;
import java.sql.Connection;
import java.sql.SQLException;
public interface IHikariStatementProxy
{
void close() throws SQLException;
void setConnectionProxy(Connection connectionProxy);
SQLException checkException(SQLException e);
}

@ -40,7 +40,7 @@ public final class JavassistProxyFactoryFactory
{
private static final ProxyFactory proxyFactory;
private static ClassPool classPool;
private ClassPool classPool;
static
{
@ -178,7 +178,7 @@ public final class JavassistProxyFactoryFactory
targetCt.addMethod(method);
}
}
targetCt.debugWriteFile("/tmp");
return targetCt.toClass(classPool.getClassLoader(), null);
}
}

@ -0,0 +1,60 @@
/*
* Copyright (C) 2013 Brett Wooldridge
*
* 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 or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.zaxxer.hikari.proxy;
import java.util.TimerTask;
import org.slf4j.LoggerFactory;
/**
* @author Brett Wooldridge
*/
public class LeakTask extends TimerTask
{
private final long leakTime;
private StackTraceElement[] stackTrace;
public LeakTask(StackTraceElement[] stackTrace, long leakDetectionThreshold)
{
this.stackTrace = stackTrace;
this.leakTime = System.currentTimeMillis() + leakDetectionThreshold;
}
/** {@inheritDoc} */
@Override
public void run()
{
if (System.currentTimeMillis() > leakTime)
{
Exception e = new Exception();
e.setStackTrace(stackTrace);
LoggerFactory.getLogger(LeakTask.class).warn("Connection leak detection triggered, stack trace follows", e);
stackTrace = null;
}
}
@Override
public boolean cancel()
{
boolean cancelled = super.cancel();
if (cancelled)
{
stackTrace = null;
}
return cancelled;
}
}

@ -20,109 +20,47 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.zaxxer.hikari.javassist.HikariInject;
/**
*
* @author Brett Wooldridge
*/
public class PreparedStatementProxy extends HikariProxyBase
{
private static final ProxyFactory PROXY_FACTORY;
private final ConnectionProxy connection;
protected final PreparedStatement delegate;
static
public class PreparedStatementProxy extends StatementProxy
{
PROXY_FACTORY = JavassistProxyFactoryFactory.getProxyFactory();
}
protected PreparedStatementProxy(ConnectionProxy connection, PreparedStatement statement)
{
this.connection = connection;
this.delegate = statement;
}
protected SQLException checkException(SQLException e)
{
return connection.checkException(e);
super(connection, statement);
}
// **********************************************************************
// Overridden java.sql.PreparedStatement Methods
// other methods are injected
// **********************************************************************
public void close() throws SQLException
{
if (delegate == null)
{
return;
}
connection.unregisterStatement(this);
delegate.close();
}
public ResultSet getResultSet() throws SQLException
{
ResultSet resultSet = delegate.getResultSet();
if (resultSet == null)
{
return null;
}
return PROXY_FACTORY.getProxyResultSet((PreparedStatement) this, resultSet);
}
@HikariInject
public ResultSet executeQuery() throws SQLException
{
ResultSet resultSet = delegate.executeQuery();
if (resultSet == null)
{
return null;
}
return PROXY_FACTORY.getProxyResultSet((PreparedStatement) this, resultSet);
IHikariResultSetProxy resultSet = (IHikariResultSetProxy) __executeQuery();
resultSet.setProxyStatement(this);
return (ResultSet) resultSet;
}
public ResultSet executeQuery(String sql) throws SQLException
{
ResultSet resultSet = delegate.executeQuery(sql);
if (resultSet == null)
{
return null;
}
return PROXY_FACTORY.getProxyResultSet((PreparedStatement) this, resultSet);
}
// ***********************************************************************
// These methods contain code we do not want injected into the actual
// java.sql.Connection implementation class. These methods are only
// used when instrumentation is not available and "conventional" Javassist
// delegating proxies are used.
// ***********************************************************************
public ResultSet getGeneratedKeys() throws SQLException
public ResultSet __executeQuery() throws SQLException
{
ResultSet generatedKeys = delegate.getGeneratedKeys();
if (generatedKeys == null)
ResultSet resultSet = ((PreparedStatement) delegate).executeQuery();
if (resultSet == null)
{
return null;
}
return PROXY_FACTORY.getProxyResultSet((PreparedStatement) this, generatedKeys);
return PROXY_FACTORY.getProxyResultSet(this, resultSet);
}
/* java.sql.Wrapper implementation */
// TODO: fix wrapper
// public boolean isWrapperFor(Class<?> iface) throws SQLException
// {
// return iface.isAssignableFrom(delegate.getClass()) || isWrapperFor(delegate, iface);
// }
//
// @SuppressWarnings("unchecked")
// public <T> T unwrap(Class<T> iface) throws SQLException
// {
// if (iface.isAssignableFrom(delegate.getClass()))
// {
// return (T) delegate;
// }
// if (isWrapperFor(iface))
// {
// return unwrap(delegate, iface);
// }
// throw new SQLException(getClass().getName() + " is not a wrapper for " + iface);
// }
}

@ -37,7 +37,7 @@ public abstract class ProxyFactory
public abstract PreparedStatement getProxyPreparedStatement(ConnectionProxy connection, PreparedStatement statement);
public abstract ResultSet getProxyResultSet(Statement statement, ResultSet resultSet);
public abstract ResultSet getProxyResultSet(IHikariStatementProxy statement, ResultSet resultSet);
/**************************************************************************
*

@ -20,24 +20,33 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.zaxxer.hikari.javassist.HikariInject;
/**
* @author Brett Wooldridge
*/
public class ResultSetProxy extends HikariProxyBase
public class ResultSetProxy extends HikariProxyBase implements IHikariResultSetProxy
{
private final Statement statement;
@HikariInject private IHikariStatementProxy _statement;
protected final ResultSet delegate;
protected ResultSetProxy(Statement statement, ResultSet resultSet)
protected ResultSetProxy(IHikariStatementProxy statement, ResultSet resultSet)
{
this.statement = statement;
this._statement = statement;
this.delegate = resultSet;
}
protected SQLException checkException(SQLException e)
@HikariInject
public SQLException checkException(SQLException e)
{
return _statement.checkException(e);
}
@HikariInject
public void setProxyStatement(IHikariStatementProxy statement)
{
return ((HikariProxyBase) statement).checkException(e);
this._statement = statement;
}
// **********************************************************************
@ -47,6 +56,6 @@ public class ResultSetProxy extends HikariProxyBase
public Statement getStatement() throws SQLException
{
return statement;
return (Statement) _statement;
}
}

@ -16,46 +16,91 @@
package com.zaxxer.hikari.proxy;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.zaxxer.hikari.javassist.HikariInject;
/**
* @author Brett Wooldridge
*/
public class StatementProxy extends HikariProxyBase
public class StatementProxy extends HikariProxyBase implements IHikariStatementProxy
{
private static final ProxyFactory PROXY_FACTORY;
protected static ProxyFactory PROXY_FACTORY;
protected final ConnectionProxy connection;
@HikariInject protected IHikariConnectionProxy _connection;
protected final Statement delegate;
protected Statement delegate;
static
{
PROXY_FACTORY = JavassistProxyFactoryFactory.getProxyFactory();
__static();
}
protected StatementProxy(ConnectionProxy connection, Statement statement)
protected StatementProxy(IHikariConnectionProxy connection, Statement statement)
{
this.connection = connection;
this._connection = connection;
this.delegate = statement;
}
protected SQLException checkException(SQLException e)
@HikariInject
public void setConnectionProxy(Connection connection)
{
return connection.checkException(e);
this._connection = (IHikariConnectionProxy) connection;
}
@HikariInject
public SQLException checkException(SQLException e)
{
return _connection.checkException(e);
}
// **********************************************************************
// Overridden java.sql.Statement Methods
// other methods are injected
// **********************************************************************
@HikariInject
public void close() throws SQLException
{
connection.unregisterStatement(this);
_connection.unregisterStatement(this);
__close();
}
public ResultSet executeQuery(String sql) throws SQLException
{
IHikariResultSetProxy resultSet = (IHikariResultSetProxy) __executeQuery(sql);
resultSet.setProxyStatement(this);
return (ResultSet) resultSet;
}
public ResultSet getGeneratedKeys() throws SQLException
{
IHikariResultSetProxy resultSet = (IHikariResultSetProxy) __getGeneratedKeys();
resultSet.setProxyStatement(this);
return (ResultSet) resultSet;
}
// ***********************************************************************
// These methods contain code we do not want injected into the actual
// java.sql.Connection implementation class. These methods are only
// used when instrumentation is not available and "conventional" Javassist
// delegating proxies are used.
// ***********************************************************************
private static void __static()
{
if (PROXY_FACTORY == null)
{
PROXY_FACTORY = JavassistProxyFactoryFactory.getProxyFactory();
}
}
public void __close() throws SQLException
{
if (delegate.isClosed())
{
return;
@ -64,7 +109,7 @@ public class StatementProxy extends HikariProxyBase
delegate.close();
}
public ResultSet executeQuery(String sql) throws SQLException
public ResultSet __executeQuery(String sql) throws SQLException
{
ResultSet resultSet = delegate.executeQuery(sql);
if (resultSet == null)
@ -72,10 +117,10 @@ public class StatementProxy extends HikariProxyBase
return null;
}
return PROXY_FACTORY.getProxyResultSet((Statement) this, resultSet);
return PROXY_FACTORY.getProxyResultSet(this, resultSet);
}
public ResultSet getGeneratedKeys() throws SQLException
public ResultSet __getGeneratedKeys() throws SQLException
{
ResultSet generatedKeys = delegate.getGeneratedKeys();
if (generatedKeys == null)
@ -83,28 +128,8 @@ public class StatementProxy extends HikariProxyBase
return null;
}
return PROXY_FACTORY.getProxyResultSet((Statement) this, generatedKeys);
return PROXY_FACTORY.getProxyResultSet(this, generatedKeys);
}
/* java.sql.Wrapper implementation */
// TODO: fix wrapper
// public boolean isWrapperFor(Class<?> iface) throws SQLException
// {
// return iface.isAssignableFrom(delegate.getClass()) || isWrapperFor(delegate, iface);
// }
//
// @SuppressWarnings("unchecked")
// public <T> T unwrap(Class<T> iface) throws SQLException
// {
// if (iface.isAssignableFrom(delegate.getClass()))
// {
// return (T) delegate;
// }
// if (isWrapperFor(iface))
// {
// return unwrap(delegate, iface);
// }
// throw new SQLException(getClass().getName() + " is not a wrapper for " + iface);
// }
}

@ -41,6 +41,13 @@ import java.util.concurrent.Executor;
*/
public class StubConnection implements Connection
{
private static long foo;
static
{
foo = System.currentTimeMillis();
}
/** {@inheritDoc} */
public <T> T unwrap(Class<T> iface) throws SQLException
{
@ -200,7 +207,7 @@ public class StubConnection implements Connection
/** {@inheritDoc} */
public int getHoldability() throws SQLException
{
return 0;
return (int) foo;
}
/** {@inheritDoc} */

@ -84,7 +84,7 @@ public class Benchmark1
config.setIdleTimeout(TimeUnit.MINUTES.toMillis(30));
config.setJdbc4ConnectionTest(true);
config.setPoolName("This has spaces");
config.setDataSourceClassName("com.zaxxer.hikari.performance.StubDataSource");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
HikariDataSource ds = new HikariDataSource(config);
return ds;

Loading…
Cancel
Save