Add a ConnectionWrapper interface to allow access to the underlying connection from a BorrowedConnectionProxy

Description

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.

Environment

Hibernate 3.1.3, Oracle 9.2.0.4

Activity

Show:
Adrian Riley
December 4, 2006, 2:09 PM

Maybe I'm being stupid here, but this doesn't seem to work.

Calling getWrappedConnection() results in a call to the invoke() method of BorrowedConnectionProxy, which then calls ConnectionManager.getConnection(). This returns the NewProxyConnection which wraps the underlying Oracle Connection instance, and not the underlying connection itself. Calling ArrayDescriptor.createArrayDescriptor passing this connection results in a ClassCastException, exactly as before.

Have I missed something?

Adrian Riley
December 4, 2006, 2:16 PM

Sorry, of course it does work when using the built in JDBC connection pool, but not when using C3P0.

Steve Ebersole
December 4, 2006, 3:20 PM

Of course its "working" when using C3P0; at least this is the same behavior Hibernate always exhibited here. The wrapped connection, from Hibernate's perspective, is the C3P0 wrapped connection (C3P0 defines this NewProxyConnection, not HIbernate).

Adrian Riley
December 4, 2006, 4:25 PM

Yes, sorry, I realised that after posting. Thanks

Steve Ebersole
March 21, 2011, 7:05 PM

Bulk closing stale resolved issues

Fixed

Assignee

Steve Ebersole

Reporter

Nick Reid

Fix versions

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

Priority

Major
Configure