[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-1737) The new BorrowedConnectionProxy prevents users from accessing the native connection

Steve Sarandos (JIRA) noreply at atlassian.com
Wed Oct 11 12:23:24 EDT 2006


    [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1737?page=comments#action_24772 ] 

Steve Sarandos commented on HHH-1737:
-------------------------------------

I ran into this issue when trying to call a stored procedure that requires an array argument.  To pass an array using Oracle's JDBC driver you need to call ArrayDescriptor.createDescriptor() passing the Oracle array type name.  Calling this method now fails with a ClassCastException due to the fact that the connection is proxied.

To solve this I added a new getConnectionProxyInterfaces() method to the Dialect class.  The default implementation returns a Class array containing the java.sql.Connection class.  This essentially causing the BorrowedConnectionProxy class to behave as it does now.  To solve my Oracle-specific problem I overrode the getConnectionProxyInterfaces() method in Oracle9Dialect and had it return an array of interface classes containing the Oracle-specific connection interface(oracle.jdbc.OracleConnection).  It uses interface names and looks them up through reflection to prevent any dependency on the Oracle JDBC driver:

	public Class[] getConnectionProxyInterfaces() {
		String[] interfaceNames = new String[] {"java.sql.Connection", "oracle.jdbc.OracleConnection"};
		Class[] interfaces = new Class[2];

		for (int i = 0; i < interfaces.length; i++) {
			try {
				interfaces[i] = ReflectHelper.classForName(interfaceNames[i]);
			} catch (Exception se) {
				throw new HibernateException("Problem while trying to load Oracle connection interfaces.",se);
			}
		}

		return interfaces;
	}

BorrowedConnectionProxy's  generateProxy method changes to this:

	public static Connection generateProxy(ConnectionManager connectionManager) {
		BorrowedConnectionProxy handler = new BorrowedConnectionProxy( connectionManager );
		Dialect dialect = connectionManager.getFactory().getDialect();

		return ( Connection ) Proxy.newProxyInstance(
				Thread.currentThread().getContextClassLoader(),
		        dialect.getConnectionProxyInterfaces(),
		        handler
		);
	}

This allows Hibernate to keep the protection of the proxy and still allow for access to vendor specific functionality.  

> The new BorrowedConnectionProxy prevents users from accessing the native connection
> -----------------------------------------------------------------------------------
>
>          Key: HHH-1737
>          URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1737
>      Project: Hibernate3
>         Type: Bug

>   Components: core
>     Versions: 3.1.1, 3.1.2, 3.1.3
>  Environment: Hibernate 3.1.3, Oracle 9.2.0.4
>     Reporter: Nick Reid

>
>
> The borrowConnection functionality now prevents us from accessing the native connection to perform necessary operations (LOB handling, OAQ integration).  Instead of just returning a simple proxy the implements java.sql.Connection the proxy could additionally implement an interface that allows users to access the wrapped connection returned by the ConnectionManager.
> i.e.
> public interface BorrowedConnection extends java.sql.Connection
> {
>      java.sql.Connection getTargetConnection()
> }
> public class BorrowedConnectionProxy implements InvocationHandler {
> 	private final ConnectionManager connectionManager;
> 	private boolean useable = true;
> 	public BorrowedConnectionProxy(ConnectionManager connectionManager) {
> 		this.connectionManager = connectionManager;
> 	}
> 	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
> 		if ( "close".equals( method.getName() ) ) {
> 			connectionManager.releaseBorrowedConnection();
> 			return null;
> 		}
> 		if ( "getTargetConnection".equals( method.getName() ) ) {
> 			return connectionManager.getConnection();
> 		}
> 		// should probably no-op commit/rollback here, at least in JTA scenarios
> 		if ( !useable ) {
> 			throw new HibernateException( "connnection proxy not usable after transaction completion" );
> 		}
> 		try {
> 			return method.invoke( connectionManager.getConnection(), args );
> 		}
> 		catch( InvocationTargetException e ) {
> 			throw e.getTargetException();
> 		}
> 	}
> 	public static Connection generateProxy(ConnectionManager connectionManager) {
> 		BorrowedConnectionProxy handler = new BorrowedConnectionProxy( connectionManager );
> 		return ( Connection ) Proxy.newProxyInstance(
> 				Connection.class.getClassLoader(),
> 		        new Class[] { BorrowedConnection.class },
> 		        handler
> 		);
> 	}
> 	public static void renderUnuseable(Connection connection) {
> 		if ( connection != null && Proxy.isProxyClass( connection.getClass() ) ) {
> 			InvocationHandler handler = Proxy.getInvocationHandler( connection );
> 			if ( BorrowedConnectionProxy.class.isAssignableFrom( handler.getClass() ) ) {
> 				( ( BorrowedConnectionProxy ) handler ).useable = false;
> 			}
> 		}
> 	}
> }
> We could always get access to the connectionManager field of the invocation handler via reflection, but this is not supportable or maintainable.

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira




More information about the hibernate-issues mailing list