FileDocCategorySizeDatePackage
ConnectionManager.javaAPI DocHibernate 3.2.515452Mon Mar 19 16:06:46 GMT 2007org.hibernate.jdbc

ConnectionManager

public class ConnectionManager extends Object implements Serializable
Encapsulates JDBC Connection management logic needed by Hibernate.

The lifecycle is intended to span a logical series of interactions with the database. Internally, this means the the lifecycle of the Session.

author
Steve Ebersole

Fields Summary
private static final Log
log
private transient org.hibernate.engine.SessionFactoryImplementor
factory
private final Callback
callback
private final org.hibernate.ConnectionReleaseMode
releaseMode
private transient Connection
connection
private transient Connection
borrowedConnection
private final boolean
wasConnectionSupplied
private transient Batcher
batcher
private transient org.hibernate.Interceptor
interceptor
private boolean
isClosed
private transient boolean
isFlushing
Constructors Summary
public ConnectionManager(org.hibernate.engine.SessionFactoryImplementor factory, Callback callback, org.hibernate.ConnectionReleaseMode releaseMode, Connection connection, org.hibernate.Interceptor interceptor)
Constructs a ConnectionManager.

This is the form used internally.

param
factory The SessionFactory.
param
callback An observer for internal state change.
param
releaseMode The mode by which to release JDBC connections.
param
connection An externally supplied connection.

 
	                                       	  
	 
	         
	         
	         
	         
	          
		this.factory = factory;
		this.callback = callback;

		this.interceptor = interceptor;
		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );

		this.connection = connection;
		wasConnectionSupplied = ( connection != null );

		this.releaseMode = wasConnectionSupplied ? ConnectionReleaseMode.ON_CLOSE : releaseMode;
	
private ConnectionManager(org.hibernate.engine.SessionFactoryImplementor factory, Callback callback, org.hibernate.ConnectionReleaseMode releaseMode, org.hibernate.Interceptor interceptor, boolean wasConnectionSupplied, boolean isClosed)
Private constructor used exclusively from custom serialization

		this.factory = factory;
		this.callback = callback;

		this.interceptor = interceptor;
		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );

		this.wasConnectionSupplied = wasConnectionSupplied;
		this.isClosed = isClosed;
		this.releaseMode = wasConnectionSupplied ? ConnectionReleaseMode.ON_CLOSE : releaseMode;
	
Methods Summary
public voidafterStatement()
To be called after execution of each JDBC statement. Used to conditionally release the JDBC connection aggressively if the configured release mode indicates.

		if ( isAggressiveRelease() ) {
			if ( isFlushing ) {
				log.debug( "skipping aggressive-release due to flush cycle" );
			}
			else if ( batcher.hasOpenResources() ) {
				log.debug( "skipping aggresive-release due to open resources on batcher" );
			}
			else if ( borrowedConnection != null ) {
				log.debug( "skipping aggresive-release due to borrowed connection" );
			}
			else {
				aggressiveRelease();
			}
		}
	
public voidafterTransaction()
To be called after local transaction completion. Used to conditionally release the JDBC connection aggressively if the configured release mode indicates.

		if ( isAfterTransactionRelease() ) {
			aggressiveRelease();
		}
		else if ( isAggressiveReleaseNoTransactionCheck() && batcher.hasOpenResources() ) {
			log.info( "forcing batcher resource cleanup on transaction completion; forgot to close ScrollableResults/Iterator?" );
			batcher.closeStatements();
			aggressiveRelease();
		}
		else if ( isOnCloseRelease() ) {
			// log a message about potential connection leaks
			log.debug( "transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!" );
		}
		batcher.unsetTransactionTimeout();
	
private voidaggressiveRelease()
Performs actions required to perform an aggressive release of the JDBC Connection.

		if ( !wasConnectionSupplied ) {
			log.debug( "aggressively releasing JDBC connection" );
			if ( connection != null ) {
				closeConnection();
			}
		}
	
public java.sql.ConnectionborrowConnection()

		if ( isClosed ) {
			throw new HibernateException( "connection manager has been closed" );
		}
		if ( isSuppliedConnection() ) {
			return connection;
		}
		else {
			if ( borrowedConnection == null ) {
				borrowedConnection = BorrowedConnectionProxy.generateProxy( this );
			}
			return borrowedConnection;
		}
	
private java.sql.Connectioncleanup()
Releases the Connection and cleans up any resources associated with that Connection. This is intended for use: 1) at the end of the session 2) on a manual disconnect of the session 3) from afterTransaction(), in the case of skipped aggressive releasing

return
The released connection.
throws
HibernateException

		releaseBorrowedConnection();

		if ( connection == null ) {
			log.trace( "connection already null in cleanup : no action");
			return null;
		}

		try {
			log.trace( "performing cleanup" );

			batcher.closeStatements();
			Connection c = null;
			if ( !wasConnectionSupplied ) {
				closeConnection();
			}
			else {
				c = connection;
			}
			connection = null;
			return c;
		}
		finally {
			callback.connectionCleanedUp();
		}
	
public java.sql.Connectionclose()
To be called after Session completion. Used to release the JDBC connection.

return
The connection mantained here at time of close. Null if there was no connection cached internally.

		try {
			return cleanup();
		}
		finally {
			isClosed = true;
		}
	
private voidcloseConnection()
Physically closes the JDBC Connection.

		if ( log.isDebugEnabled() ) {
			log.debug(
					"releasing JDBC connection [" +
					batcher.openResourceStatsAsString() + "]"
				);
		}

		try {
			if ( !connection.isClosed() ) {
				JDBCExceptionReporter.logAndClearWarnings( connection );
			}
			factory.getConnectionProvider().closeConnection( connection );
			connection = null;
		}
		catch (SQLException sqle) {
			throw JDBCExceptionHelper.convert( 
					factory.getSQLExceptionConverter(), 
					sqle, 
					"Cannot release connection"
				);
		}
	
public static org.hibernate.jdbc.ConnectionManagerdeserialize(java.io.ObjectInputStream ois, org.hibernate.engine.SessionFactoryImplementor factory, org.hibernate.Interceptor interceptor, org.hibernate.ConnectionReleaseMode connectionReleaseMode, JDBCContext jdbcContext)

		return new ConnectionManager(
				factory,
		        jdbcContext,
		        connectionReleaseMode,
		        interceptor,
		        ois.readBoolean(),
		        ois.readBoolean()
		);
	
public voidflushBeginning()
Callback to let us know that a flush is beginning. We use this fact to temporarily circumvent aggressive connection releasing until after the flush cycle is complete {@link #flushEnding()}

		log.trace( "registering flush begin" );
		isFlushing = true;
	
public voidflushEnding()
Callback to let us know that a flush is ending. We use this fact to stop circumventing aggressive releasing connections.

		log.trace( "registering flush end" );
		isFlushing = false;
		afterStatement();
	
public BatchergetBatcher()
The batcher managed by this ConnectionManager.

return
The batcher.

		return batcher;
	
public java.sql.ConnectiongetConnection()
Retrieves the connection currently managed by this ConnectionManager.

Note, that we may need to obtain a connection to return here if a connection has either not yet been obtained (non-UserSuppliedConnectionProvider) or has previously been aggressively released (if supported in this environment).

return
The current Connection.
throws
HibernateException Indicates a connection is currently not available (we are currently manually disconnected).

		if ( isClosed ) {
			throw new HibernateException( "connection manager has been closed" );
		}
		if ( connection == null  ) {
			openConnection();
		}
		return connection;
	
public org.hibernate.engine.SessionFactoryImplementorgetFactory()
The session factory.

return
the session factory.

		return factory;
	
public booleanhasBorrowedConnection()

		// used from testsuite
		return borrowedConnection != null;
	
private booleanisAfterTransactionRelease()

		return releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION;
	
public booleanisAggressiveRelease()
Will connections be released after each statement execution?

Connections will be released after each statement if either:

  • the defined release-mode is {@link ConnectionReleaseMode#AFTER_STATEMENT}; or
  • the defined release-mode is {@link ConnectionReleaseMode#AFTER_TRANSACTION} but we are in auto-commit mode.

    release-mode = {@link ConnectionReleaseMode#ON_CLOSE} should [b]never[/b] release a connection.

    return
    True if the connections will be released after each statement; false otherwise.

    		if ( releaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
    			return true;
    		}
    		else if ( releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION ) {
    			boolean inAutoCommitState;
    			try {
    				inAutoCommitState = isAutoCommit()&& !callback.isTransactionInProgress();
    			}
    			catch( SQLException e ) {
    				// assume we are in an auto-commit state
    				inAutoCommitState = true;
    			}
    			return inAutoCommitState;
    		}
    		return false;
    	
private booleanisAggressiveReleaseNoTransactionCheck()
Modified version of {@link #isAggressiveRelease} which does not force a transaction check. This is solely used from our {@link #afterTransaction} callback, so no need to do the check; plus it seems to cause problems on websphere (god i love websphere ;)

It uses this information to decide if an aggressive release was skipped do to open resources, and if so forces a release.

return
True if the connections will be released after each statement; false otherwise.

		if ( releaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) {
			return true;
		}
		else {
			boolean inAutoCommitState;
			try {
				inAutoCommitState = isAutoCommit();
			}
			catch( SQLException e ) {
				// assume we are in an auto-commit state
				inAutoCommitState = true;
			}
			return releaseMode == ConnectionReleaseMode.AFTER_TRANSACTION && inAutoCommitState;
		}
	
public booleanisAutoCommit()
Is the connection considered "auto-commit"?

return
True if we either do not have a connection, or the connection really is in auto-commit mode.
throws
SQLException Can be thrown by the Connection.isAutoCommit() check.

		return connection == null 
			|| connection.isClosed()
			|| connection.getAutoCommit();
	
public booleanisCurrentlyConnected()
Is this ConnectionManager instance "logically" connected. Meaning do we either have a cached connection available or do we have the ability to obtain a connection on demand.

return
True if logically connected; false otherwise.

		return wasConnectionSupplied ? connection != null : !isClosed;
	
private booleanisOnCloseRelease()

		return releaseMode == ConnectionReleaseMode.ON_CLOSE;
	
public booleanisReadyForSerialization()

		return wasConnectionSupplied ? connection == null : !batcher.hasOpenResources();
	
public booleanisSuppliedConnection()
Was the connection being used here supplied by the user?

return
True if the user supplied the JDBC connection; false otherwise

		return wasConnectionSupplied;
	
public java.sql.ConnectionmanualDisconnect()
Manually disconnect the underlying JDBC Connection. The assumption here is that the manager will be reconnected at a later point in time.

return
The connection mantained here at time of disconnect. Null if there was no connection cached internally.

		return cleanup();
	
public voidmanualReconnect()
Manually reconnect the underlying JDBC Connection. Should be called at some point after manualDisconnect().

This form is used for ConnectionProvider-supplied connections.

	
public voidmanualReconnect(java.sql.Connection suppliedConnection)
Manually reconnect the underlying JDBC Connection. Should be called at some point after manualDisconnect().

This form is used for user-supplied connections.

		this.connection = suppliedConnection;
	
private voidopenConnection()
Pysically opens a JDBC Connection.

throws
HibernateException

		if ( connection != null ) {
			return;
		}

		log.debug("opening JDBC connection");
		try {
			connection = factory.getConnectionProvider().getConnection();
		}
		catch (SQLException sqle) {
			throw JDBCExceptionHelper.convert(
					factory.getSQLExceptionConverter(),
					sqle,
					"Cannot open connection"
				);
		}

		callback.connectionOpened(); // register synch; stats.connect()
	
private voidreadObject(java.io.ObjectInputStream ois)
Used during deserialization.

param
ois The stream from which we are being read.
throws
IOException Indicates an I/O error reading the stream
throws
ClassNotFoundException Indicates resource class resolution.

		factory = (SessionFactoryImplementor) ois.readObject();
		interceptor = (Interceptor) ois.readObject();
		ois.defaultReadObject();

		this.batcher = factory.getSettings().getBatcherFactory().createBatcher( this, interceptor );
	
public voidreleaseBorrowedConnection()

		if ( borrowedConnection != null ) {
			try {
				BorrowedConnectionProxy.renderUnuseable( borrowedConnection );
			}
			finally {
				borrowedConnection = null;
			}
		}
	
public voidserialize(java.io.ObjectOutputStream oos)

		oos.writeBoolean( wasConnectionSupplied );
		oos.writeBoolean( isClosed );
	
private voidwriteObject(java.io.ObjectOutputStream oos)
Used during serialization.

param
oos The stream to which we are being written.
throws
IOException Indicates an I/O error writing to the stream

		if ( !isReadyForSerialization() ) {
			throw new IllegalStateException( "Cannot serialize a ConnectionManager while connected" );
		}

		oos.writeObject( factory );
		oos.writeObject( interceptor );
		oos.defaultWriteObject();