Open Source Repository

Home /hibernate/hibernate-3.2.6.ga | Repository Home


org/hibernate/jdbc/BorrowedConnectionProxy.java
package org.hibernate.jdbc;

import org.hibernate.HibernateException;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;

/**
 * A proxy for <i>borrowed</i> connections which funnels all requests back
 * into the ConnectionManager from which it was borrowed to be properly
 * handled (in terms of connection release modes).
 <p/>
 * Note: the term borrowed here refers to connection references obtained
 * via {@link org.hibernate.Session#connection()} for application usage.
 *
 @author Steve Ebersole
 */
public class BorrowedConnectionProxy implements InvocationHandler {

  private static final Class[] PROXY_INTERFACES = new Class[] { Connection.class, ConnectionWrapper.class };

  private final ConnectionManager connectionManager;
  private boolean useable = true;

  public BorrowedConnectionProxy(ConnectionManager connectionManager) {
    this.connectionManager = connectionManager;
  }

  /**
   * {@inheritDoc}
   */
  public Object invoke(Object proxy, Method method, Object[] argsthrows Throwable {
    if "close".equalsmethod.getName() ) ) {
      connectionManager.releaseBorrowedConnection();
      return null;
    }
    // should probably no-op commit/rollback here, at least in JTA scenarios
    if !useable ) {
      throw new HibernateException"connnection proxy not usable after transaction completion" );
    }

    if "getWrappedConnection".equalsmethod.getName() ) ) {
      return connectionManager.getConnection();
    }

    try {
      return method.invokeconnectionManager.getConnection(), args );
    }
    catchInvocationTargetException e ) {
      throw e.getTargetException();
    }
  }

  /**
   * Generates a Connection proxy wrapping the connection managed by the passed
   * connection manager.
   *
   @param connectionManager The connection manager to wrap with the
   * connection proxy.
   @return The generated proxy.
   */
  public static Connection generateProxy(ConnectionManager connectionManager) {
    BorrowedConnectionProxy handler = new BorrowedConnectionProxyconnectionManager );
    return Connection Proxy.newProxyInstance(
        getProxyClassLoader(),
            PROXY_INTERFACES,
            handler
    );
  }

  /**
   * Marks a borrowed connection as no longer usable.
   *
   @param connection The connection (proxy) to be marked.
   */
  public static void renderUnuseable(Connection connection) {
    if connection != null && Proxy.isProxyClassconnection.getClass() ) ) {
      InvocationHandler handler = Proxy.getInvocationHandlerconnection );
      if BorrowedConnectionProxy.class.isAssignableFromhandler.getClass() ) ) {
        ( ( BorrowedConnectionProxy handler ).useable = false;
      }
    }
  }

  /**
   * Convience method for unwrapping a connection proxy and getting a
   * handle to an underlying connection.
   *
   @param connection The connection (proxy) to be unwrapped.
   @return The unwrapped connection.
   */
  public static Connection getWrappedConnection(Connection connection) {
    if connection != null && connection instanceof ConnectionWrapper ) {
      return ( ( ConnectionWrapper connection ).getWrappedConnection();
    }
    else {
      return connection;
    }
  }

  /**
   * Determines the appropriate class loader to which the generated proxy
   * should be scoped.
   *
   @return The class loader appropriate for proxy construction.
   */
  public static ClassLoader getProxyClassLoader() {
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    if cl == null ) {
      cl = BorrowedConnectionProxy.class.getClassLoader();
    }
    return cl;
  }
}