Author: steve.ebersole(a)jboss.com
Date: 2007-08-10 01:35:01 -0400 (Fri, 10 Aug 2007)
New Revision: 12914
Added:
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/PreparedStatementProxy.java
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/ResultSetProxy.java
Modified:
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/JDBCContainer.java
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/impl/BasicJDBCContainer.java
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/AbstractStatementProxy.java
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/ConnectionProxy.java
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/StatementProxy.java
sandbox/trunk/jdbc-proxy/src/test/java/org/hibernate/jdbc/proxy/BasicConnectionProxyTest.java
sandbox/trunk/jdbc-proxy/src/test/resources/log4j.properties
Log:
more proxy-based jdbc interaction checkins
Modified: sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/JDBCContainer.java
===================================================================
---
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/JDBCContainer.java 2007-08-09
20:10:00 UTC (rev 12913)
+++
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/JDBCContainer.java 2007-08-10
05:35:01 UTC (rev 12914)
@@ -26,6 +26,7 @@
public interface JDBCContainer {
public void register(Statement statement);
public void release(Statement statement);
+
public void register(ResultSet resultSet);
public void release(ResultSet resultSet);
Modified:
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/impl/BasicJDBCContainer.java
===================================================================
---
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/impl/BasicJDBCContainer.java 2007-08-09
20:10:00 UTC (rev 12913)
+++
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/impl/BasicJDBCContainer.java 2007-08-10
05:35:01 UTC (rev 12914)
@@ -17,7 +17,6 @@
import java.sql.Statement;
import java.sql.ResultSet;
-import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Iterator;
@@ -80,10 +79,10 @@
registeredStatements.clear();
}
- protected final void close(Statement statement) {
+ protected void close(Statement statement) {
log.trace( "closing prepared statement [" + statement + "]" );
try {
- // if we are unable to "clean" the prepared statement,
+ // if we are unable to "clan" the prepared statement,
// we do not close it
try {
if ( statement.getMaxRows() != 0 ) {
@@ -105,7 +104,7 @@
}
}
- protected final void close(ResultSet resultSet) {
+ protected void close(ResultSet resultSet) {
log.trace( "closing result set [" + resultSet + "]" );
try {
resultSet.close();
Modified:
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/AbstractStatementProxy.java
===================================================================
---
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/AbstractStatementProxy.java 2007-08-09
20:10:00 UTC (rev 12913)
+++
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/AbstractStatementProxy.java 2007-08-10
05:35:01 UTC (rev 12914)
@@ -16,34 +16,48 @@
package org.hibernate.jdbc.proxy;
import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
import java.sql.Statement;
-import java.sql.SQLException;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.jdbc.JDBCContainer;
+import org.hibernate.jdbc.JDBCServices;
+
/**
* AbstractStatementProxy implementation
*
* @author Steve Ebersole
*/
public abstract class AbstractStatementProxy implements InvocationHandler {
- private final String sql;
- private final Statement statement;
- private final ConnectionProxy connectionProxy;
- private Set resultSets;
+ public static final Class[] PROXY_INTERFACES = new Class[] { Statement.class };
+ public static final Class[] PS_PROXY_INTERFACES = new Class[] { PreparedStatement.class
};
+ public static final Class[] CS_PROXY_INTERFACES = new Class[] { CallableStatement.class
};
- protected AbstractStatementProxy(String sql, Statement statement, ConnectionProxy
connectionProxy) {
- this.sql = sql;
+ private static final Logger log = LoggerFactory.getLogger( AbstractStatementProxy.class
);
+
+ private boolean valid = true;
+ private Statement statement;
+ private ConnectionProxy connectionProxy;
+ private Set resultSetProxies;
+
+ protected AbstractStatementProxy(Statement statement, ConnectionProxy connectionProxy)
{
this.statement = statement;
this.connectionProxy = connectionProxy;
+ getJdbcContainer().register( statement );
}
- protected String getSql() {
- return sql;
- }
-
protected Statement getStatement() {
return statement;
}
@@ -52,20 +66,56 @@
return connectionProxy;
}
- protected Set getResultSets() {
- return resultSets;
+ protected Set getResultSetProxies() {
+ return resultSetProxies;
}
- protected Set getOrCreateResultSets() {
- if ( resultSets == null ) {
- resultSets = new HashSet();
+ protected JDBCServices getJdbcServices() {
+ return getConnectionProxy().getJdbcServices();
+ }
+
+ protected JDBCContainer getJdbcContainer() {
+ return getConnectionProxy().getJdbcContainer();
+ }
+
+ protected Set getOrCreateResultSetProxies() {
+ if ( resultSetProxies == null ) {
+ resultSetProxies = new HashSet();
}
- return resultSets;
+ return resultSetProxies;
}
- protected Object invokeOnStatement(Method method, Object[] args) throws Throwable {
+ public final Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
+ String methodName = method.getName();
+ log.trace( "Handling invocation of statement method [{}]", methodName );
+
+ if ( !valid ) {
+ throw new HibernateException( "connection handle is invalid" );
+ }
+
+ if ( "close".equals( methodName ) ) {
+ explicitClose( ( Statement ) proxy );
+ return null;
+ }
+
+ beginningInvocationHandling( method, args );
+
try {
- return method.invoke( statement, args );
+ boolean exposingResultSet = doesMethodExposeResultSet( method );
+
+ Object result = method.invoke( statement, args );
+
+ if ( exposingResultSet ) {
+ ResultSetProxy handler = new ResultSetProxy( ( ResultSet ) result, this );
+ result = Proxy.newProxyInstance(
+ getClass().getClassLoader(),
+ ResultSetProxy.PROXY_INTERFACES,
+ handler
+ );
+ getOrCreateResultSetProxies().add( result );
+ }
+
+ return result;
}
catch ( InvocationTargetException e ) {
Throwable realException = e.getTargetException();
@@ -78,16 +128,39 @@
}
}
- void close(Statement statement) {
-
+ protected void beginningInvocationHandling(Method method, Object[] args) {
}
- /**
- * Release resources associated with this statement.
- *
- * NOTE : package-protected
- */
- void release() {
- // todo : eventually need to iterate results and release them
+ private void explicitClose(Statement proxy) {
+ if ( resultSetProxies != null ) {
+ Iterator itr = resultSetProxies.iterator();
+ while ( itr.hasNext() ) {
+ final ResultSet resultSetProxy = ( ResultSet ) itr.next();
+ try {
+ resultSetProxy.close();
+ }
+ catch ( SQLException e ) {
+ // should never ever happen...
+ log.warn( "unhandled SQLException escaped proxy handling!", e );
+ // but the underlying resources should still get cleaned up when the logical
connection closes...
+ }
+ itr.remove();
+ }
+ }
+ connectionProxy.getJdbcContainer().release( statement );
+ connectionProxy.proxiedStatementExplicitlyClosed( proxy );
+ statement = null;
+ connectionProxy = null;
+ resultSetProxies = null;
+ valid = false;
}
+
+ protected boolean doesMethodExposeResultSet(Method method) {
+ return ResultSet.class.isAssignableFrom( method.getReturnType() )
+ && !method.getName().equals( "getGeneratedKeys" );
+ }
+
+ /*package-protected*/ void proxiedResultSetExplicitlyClosed(ResultSet proxy) {
+ resultSetProxies.remove( proxy );
+ }
}
Modified:
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/ConnectionProxy.java
===================================================================
---
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/ConnectionProxy.java 2007-08-09
20:10:00 UTC (rev 12913)
+++
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/ConnectionProxy.java 2007-08-10
05:35:01 UTC (rev 12914)
@@ -18,13 +18,20 @@
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
import java.sql.Connection;
+import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.jdbc.ConnectionWrapper;
import org.hibernate.jdbc.JDBCContainer;
import org.hibernate.jdbc.JDBCServices;
import org.hibernate.jdbc.Observer;
@@ -36,9 +43,13 @@
* @author Steve Ebersole
*/
public class ConnectionProxy implements InvocationHandler, Observer {
+ public static final Class[] PROXY_INTERFACES = new Class[] { Connection.class,
ConnectionWrapper.class };
+
private static final Logger log = LoggerFactory.getLogger( ConnectionProxy.class );
+ private boolean valid = true;
private LogicalConnectionImplementor logicalConnection;
+ private HashSet statementProxies;
public ConnectionProxy(LogicalConnectionImplementor logicalConnection) {
this.logicalConnection = logicalConnection;
@@ -47,24 +58,50 @@
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
+ log.trace( "Handling invocation of Connection method [{}]", methodName );
+ if ( !valid ) {
+ throw new HibernateException( "connection handle is invalid" );
+ }
+
if ( "getWrappedConnection".equals( methodName ) ) {
return extractPhysicalConnection();
}
- // todo : close??? depends on whether we allow multiple connection proxies on the same
logical connection
+ if ( "close".equals( methodName ) ) {
+ explicitClose();
+ return null;
+ }
try {
+ boolean creatingBasicStatement = "createStatement".equals( methodName );
+ boolean creatingPreparedStatement = "prepareStatement".equals( methodName
);
+ boolean creatingCallableStatement = "prepareCall".equals( methodName );
+
Object result = method.invoke( extractPhysicalConnection(), args );
- if ( "prepareStatement".equals( methodName )
- || "prepareCall".equals( methodName )
- || "createStatement".equals( methodName ) ) {
- getJdbcContainer().register( ( Statement ) result ); // todo : this should eventually
be the statemernt proxy
- if ( args != null && args.length > 0 ) {
- // there is a version of createStatement which does not take the SQL...
- logicalConnection.getJdbcServices().getSqlStatementLogger().logStatement( ( String )
args[0] );
+ if ( creatingBasicStatement || creatingPreparedStatement || creatingCallableStatement
) {
+ AbstractStatementProxy proxyHandler;
+ Class[] interfaces;
+ if ( creatingPreparedStatement ) {
+ proxyHandler = new PreparedStatementProxy( ( String ) args[0], ( PreparedStatement )
result, this );
+ interfaces = AbstractStatementProxy.PS_PROXY_INTERFACES;
}
+ else if ( creatingCallableStatement ) {
+ proxyHandler = new PreparedStatementProxy( ( String ) args[0], ( PreparedStatement )
result, this );
+ interfaces = AbstractStatementProxy.CS_PROXY_INTERFACES;
+ }
+ else {
+ proxyHandler = new StatementProxy( ( Statement ) result, this );
+ interfaces = AbstractStatementProxy.PROXY_INTERFACES;
+ }
+
+ result = Proxy.newProxyInstance(
+ getClass().getClassLoader(), // use our classloader
+ interfaces,
+ proxyHandler
+ );
+ getOrCreateStatementProxies().add( result );
}
return result;
@@ -80,10 +117,49 @@
}
}
+ private Set getOrCreateStatementProxies() {
+ if ( statementProxies == null ) {
+ statementProxies = new HashSet();
+ }
+ return statementProxies;
+ }
+
+ private void explicitClose() {
+ if ( statementProxies != null ) {
+ Iterator itr = statementProxies.iterator();
+ while ( itr.hasNext() ) {
+ final Statement proxy = ( Statement ) itr.next();
+ try {
+ proxy.close();
+ }
+ catch ( SQLException e ) {
+ // should never ever happen...
+ log.warn( "unhandled SQLException escaped proxy handling!", e );
+ // but the underlying resources should still get cleaned up when the logical
connection closes...
+ }
+ }
+ }
+ invalidateHandle();
+ }
+
+ private void invalidateHandle() {
+ log.trace( "Invalidating connection handle" );
+ logicalConnection = null;
+ valid = false;
+ if ( statementProxies != null ) {
+ statementProxies.clear();
+ statementProxies = null;
+ }
+ }
+
private Connection extractPhysicalConnection() {
return logicalConnection.getConnection();
}
+ /*package-protected*/ void proxiedStatementExplicitlyClosed(Statement proxy) {
+ statementProxies.remove( proxy );
+ }
+
/*package-protected*/ JDBCServices getJdbcServices() {
return logicalConnection.getJdbcServices();
}
@@ -103,7 +179,7 @@
public void logicalConnectionClosed() {
log.info( "*** logical connection closed ***" );
+ invalidateHandle();
}
-
}
Added:
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/PreparedStatementProxy.java
===================================================================
---
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/PreparedStatementProxy.java
(rev 0)
+++
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/PreparedStatementProxy.java 2007-08-10
05:35:01 UTC (rev 12914)
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details. You should have received a
+ * copy of the GNU Lesser General Public License, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Steve Ebersole
+ */
+package org.hibernate.jdbc.proxy;
+
+import java.sql.Statement;
+
+/**
+ * PreparedStatementProxy implementation
+ *
+ * @author Steve Ebersole
+ */
+public class PreparedStatementProxy extends AbstractStatementProxy {
+ private final String sql;
+
+ protected PreparedStatementProxy(String sql, Statement statement, ConnectionProxy
connectionProxy) {
+ super( statement, connectionProxy );
+ connectionProxy.getJdbcServices().getSqlStatementLogger().logStatement( sql );
+ this.sql = sql;
+ }
+}
Added:
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/ResultSetProxy.java
===================================================================
--- sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/ResultSetProxy.java
(rev 0)
+++
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/ResultSetProxy.java 2007-08-10
05:35:01 UTC (rev 12914)
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details. You should have received a
+ * copy of the GNU Lesser General Public License, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Steve Ebersole
+ */
+package org.hibernate.jdbc.proxy;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.HibernateException;
+
+/**
+ * ResultSetProxy implementation
+ *
+ * @author Steve Ebersole
+ */
+public class ResultSetProxy implements InvocationHandler {
+ public static final Class[] PROXY_INTERFACES = new Class[] { ResultSet.class };
+
+ private static final Logger log = LoggerFactory.getLogger( ResultSetProxy.class );
+
+ private boolean valid = true;
+ private ResultSet physicalResultSet;
+ private AbstractStatementProxy associatedStatementProxy;
+
+ public ResultSetProxy(ResultSet physicalResultSet, AbstractStatementProxy
associatedStatementProxy) {
+ this.physicalResultSet = physicalResultSet;
+ this.associatedStatementProxy = associatedStatementProxy;
+ associatedStatementProxy.getJdbcContainer().register( physicalResultSet );
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ String methodName = method.getName();
+ log.trace( "Handling invocation of resultset method [{}]", methodName );
+
+ if ( !valid ) {
+ throw new HibernateException( "connection handle is invalid" );
+ }
+
+ if ( "close".equals( methodName ) ) {
+ explicitClose( ( ResultSet ) proxy );
+ return null;
+ }
+
+ try {
+ return method.invoke( physicalResultSet, args );
+ }
+ catch ( InvocationTargetException e ) {
+ Throwable realException = e.getTargetException();
+ if ( SQLException.class.isInstance( realException ) ) {
+ throw associatedStatementProxy.getJdbcServices().getExceptionHelper().convert( (
SQLException ) realException, "???", "???" );
+ }
+ else {
+ throw realException;
+ }
+ }
+ }
+
+ private void explicitClose(ResultSet proxy) {
+ associatedStatementProxy.getJdbcContainer().release( physicalResultSet );
+ associatedStatementProxy.proxiedResultSetExplicitlyClosed( proxy );
+ physicalResultSet = null;
+ associatedStatementProxy = null;
+ valid = false;
+ }
+}
Modified:
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/StatementProxy.java
===================================================================
---
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/StatementProxy.java 2007-08-09
20:10:00 UTC (rev 12913)
+++
sandbox/trunk/jdbc-proxy/src/main/java/org/hibernate/jdbc/proxy/StatementProxy.java 2007-08-10
05:35:01 UTC (rev 12914)
@@ -15,8 +15,8 @@
*/
package org.hibernate.jdbc.proxy;
+import java.sql.Statement;
import java.lang.reflect.Method;
-import java.sql.Statement;
/**
* StatementProxy implementation
@@ -24,11 +24,20 @@
* @author Steve Ebersole
*/
public class StatementProxy extends AbstractStatementProxy {
- protected StatementProxy(String sql, Statement statement, ConnectionProxy
connectionProxy) {
- super( sql, statement, connectionProxy );
+ protected StatementProxy(Statement statement, ConnectionProxy connectionProxy) {
+ super( statement, connectionProxy );
}
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- return null;
+ protected void beginningInvocationHandling(Method method, Object[] args) {
+ if ( isExecution( method ) ) {
+ getJdbcServices().getSqlStatementLogger().logStatement( ( String ) args[0] );
+ }
}
+
+ private boolean isExecution(Method method) {
+ String methodName = method.getName();
+ return "execute".equals( methodName )
+ || "executeQuery".equals( methodName )
+ || "executeUpdate".equals( methodName );
+ }
}
Modified:
sandbox/trunk/jdbc-proxy/src/test/java/org/hibernate/jdbc/proxy/BasicConnectionProxyTest.java
===================================================================
---
sandbox/trunk/jdbc-proxy/src/test/java/org/hibernate/jdbc/proxy/BasicConnectionProxyTest.java 2007-08-09
20:10:00 UTC (rev 12913)
+++
sandbox/trunk/jdbc-proxy/src/test/java/org/hibernate/jdbc/proxy/BasicConnectionProxyTest.java 2007-08-10
05:35:01 UTC (rev 12914)
@@ -87,9 +87,8 @@
ps.setString( 2, "name" );
ps.execute();
-// statement and resultset proxying not yet implemented
-// ps = proxiedConnection.prepareStatement( "select * from SANDBOX_JDBC_TST"
);
-// ps.executeQuery();
+ ps = proxiedConnection.prepareStatement( "select * from SANDBOX_JDBC_TST"
);
+ ps.executeQuery();
assertTrue( logicalConnection.getJdbcContainer().hasRegisteredResources() );
}
Modified: sandbox/trunk/jdbc-proxy/src/test/resources/log4j.properties
===================================================================
--- sandbox/trunk/jdbc-proxy/src/test/resources/log4j.properties 2007-08-09 20:10:00 UTC
(rev 12913)
+++ sandbox/trunk/jdbc-proxy/src/test/resources/log4j.properties 2007-08-10 05:35:01 UTC
(rev 12914)
@@ -18,7 +18,6 @@
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
-
log4j.rootLogger=info, stdout
log4j.logger.org.hibernate=trace
\ No newline at end of file