From: <jbo...@li...> - 2006-01-17 15:07:34
|
Author: ste...@jb... Date: 2006-01-17 10:06:53 -0500 (Tue, 17 Jan 2006) New Revision: 2123 Added: trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/AbstractWorkspace.java trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/JDBCContainerImplementor.java trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/ trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/IsolatedWorkspace.java trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/JDBCIsolationDelegate.java trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/JTAIsolationDelegate.java Modified: trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/JDBCContainerImpl.java trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/IsolationDelegate.java Log: implemented initial doWorkInSeperateTransaction Added: trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/AbstractWorkspace.java =================================================================== --- trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/AbstractWorkspace.java 2006-01-17 12:14:24 UTC (rev 2122) +++ trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/AbstractWorkspace.java 2006-01-17 15:06:53 UTC (rev 2123) @@ -0,0 +1,128 @@ +package org.hibernate.jdbc3.impl; + +import org.hibernate.jdbc3.Workspace; +import org.hibernate.jdbc3.util.SQLStatementLogger; +import org.hibernate.dialect.Dialect; +import org.hibernate.JDBCException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.HashSet; +import java.util.Iterator; +import java.sql.SQLException; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractWorkspace implements Workspace { + + private static final Log log = LogFactory.getLog( AbstractWorkspace.class ); + + protected final JDBCContainerImplementor container; + protected final HashSet registeredStatements = new HashSet(); + protected final HashSet registeredResultSets = new HashSet(); + + public AbstractWorkspace(JDBCContainerImplementor container) { + this.container = container; + opened(); + log.debug( "Opened workspace [" + this + "]" ); + } + + protected void opened() { + } + + protected void closed() { + } + + public final Dialect getDialect() { + return container.getDialect(); + } + + public final SQLStatementLogger getSqlLogger() { + return container.getStatementLogger(); + } + + public final JDBCException convert(SQLException sqlException, String message) { + return container.convert( sqlException, message ); + } + + public final JDBCException convert(SQLException sqlException, String message, String sql) { + return container.convert( sqlException, message, sql ); + } + + public final void register(PreparedStatement statement) { + log.trace( "registering prepared statement [" + statement + "]" ); + registeredStatements.add( statement ); + } + + public final void release(PreparedStatement statement) { + log.trace( "releasing prepared statement [" + statement + "]" ); + registeredStatements.remove( statement ); + close( statement ); + } + + public final void register(ResultSet resultSet) { + log.trace( "registering result set [" + resultSet + "]" ); + registeredResultSets.add( resultSet ); + } + + public final void release(ResultSet resultSet) { + log.trace( "releasing result set [" + resultSet + "]" ); + registeredResultSets.remove( resultSet ); + close( resultSet ); + } + + protected final void close(PreparedStatement statement) { + log.trace( "closing prepared statement [" + statement + "]" ); + try { + // if we are unable to "clean" the prepared statement, + // we do not close it + try { + if ( statement.getMaxRows() != 0 ) { + statement.setMaxRows( 0 ); + } + if ( statement.getQueryTimeout() != 0 ) { + statement.setQueryTimeout( 0 ); + } + } + catch( SQLException sqle ) { + // there was a problem "cleaning" the prepared statement + log.debug( "Exception clearing maxRows/queryTimeout [" + sqle.getMessage() + "]" ); + return; // EARLY EXIT!!! + } + statement.close(); + } + catch( SQLException sqle ) { + log.debug( "Unable to release statement [" + sqle.getMessage() + "]" ); + } + } + + protected final void close(ResultSet resultSet) { + log.trace( "closing result set [" + resultSet + "]" ); + try { + resultSet.close(); + } + catch( SQLException e ) { + log.debug( "Unable to release result set [" + e.getMessage() + "]" ); + } + } + + public final void close() { + log.trace( "closing workspace [" + this + "]" ); + Iterator iter = registeredResultSets.iterator(); + while ( iter.hasNext() ) { + close( ( ResultSet ) iter.next() ); + } + registeredResultSets.clear(); + + iter = registeredStatements.iterator(); + while ( iter.hasNext() ) { + close( ( PreparedStatement ) iter.next() ); + } + registeredStatements.clear(); + + closed(); + } +} Modified: trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/JDBCContainerImpl.java =================================================================== --- trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/JDBCContainerImpl.java 2006-01-17 12:14:24 UTC (rev 2122) +++ trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/JDBCContainerImpl.java 2006-01-17 15:06:53 UTC (rev 2123) @@ -29,7 +29,7 @@ /** * @author Steve Ebersole */ -public class JDBCContainerImpl implements JDBCContainer, Serializable { +public class JDBCContainerImpl implements JDBCContainer, JDBCContainerImplementor, Serializable { // TODO : workspace registration at a higher level: // would love to explore the idea of being able to register a workspace at a @@ -94,13 +94,10 @@ } public void doWorkInSeperateTransaction(Work work) throws HibernateException { - IsolatedWorkspaceImpl workspace = new IsolatedWorkspaceImpl(); - try { - transactionCoordinator.getIsolationDelegate().doWorkInIsolation( work, workspace ); + if ( !work.isConcise() ) { + throw new HibernateException( "non-concise work cannot be done in seperate transaction" ); } - finally { - workspace.close(); - } + transactionCoordinator.getIsolationDelegate().doWorkInIsolation( work, this ); } public void release(Work work) { @@ -117,8 +114,25 @@ } } - // SQLException conversion methods (convenience) ~~~~~~~~~~~~~~~~~~~~~~~~~~ + // JDBCContainerImplementor impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public Dialect getDialect() { + return dialect; + } + + public SQLStatementLogger getStatementLogger() { + return sqlStatementLogger; + } + + public ConnectionProvider getConnectionProvider() { + return connectionProvider; + } + + public StatisticsImplementor getStatistics() { + return stats; + } + public JDBCException convert(SQLException sqle, String message) { return JDBCExceptionHelper.convert( sqlExceptionConverter, sqle, message ); } @@ -214,151 +228,14 @@ } - // Workspace impls ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Workspace impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - public abstract class AbstractWorkspaceImpl implements Workspace { - - protected final HashSet registeredStatements = new HashSet(); - protected final HashSet registeredResultSets = new HashSet(); - - public AbstractWorkspaceImpl() { - log.debug( "Opening workspace [" + this + "]" ); - opened(); + public class WorkspaceImpl extends AbstractWorkspace implements Workspace { + public WorkspaceImpl() { + super( JDBCContainerImpl.this ); } - protected void opened() { - } - - protected void closed() { - } - - public final Dialect getDialect() { - return JDBCContainerImpl.this.dialect; - } - - public final SQLStatementLogger getSqlLogger() { - return JDBCContainerImpl.this.sqlStatementLogger; - } - - public final JDBCException convert(SQLException sqlException, String message) { - return JDBCContainerImpl.this.convert( sqlException, message ); - } - - public final JDBCException convert(SQLException sqlException, String message, String sql) { - return JDBCContainerImpl.this.convert( sqlException, message, sql ); - } - - public final void register(PreparedStatement statement) { - log.trace( "registering prepared statement [" + statement + "]" ); - registeredStatements.add( statement ); - } - - public final void release(PreparedStatement statement) { - log.trace( "releasing prepared statement [" + statement + "]" ); - registeredStatements.remove( statement ); - close( statement ); - } - - public final void register(ResultSet resultSet) { - log.trace( "registering result set [" + resultSet + "]" ); - registeredResultSets.add( resultSet ); - } - - public final void release(ResultSet resultSet) { - log.trace( "releasing result set [" + resultSet + "]" ); - registeredResultSets.remove( resultSet ); - close( resultSet ); - } - - protected final void close(PreparedStatement statement) { - log.trace( "closing prepared statement [" + statement + "]" ); - try { - // if we are unable to "clean" the prepared statement, - // we do not close it - try { - if ( statement.getMaxRows() != 0 ) { - statement.setMaxRows( 0 ); - } - if ( statement.getQueryTimeout() != 0 ) { - statement.setQueryTimeout( 0 ); - } - } - catch( SQLException sqle ) { - // there was a problem "cleaning" the prepared statement - log.debug( "Exception clearing maxRows/queryTimeout [" + sqle.getMessage() + "]" ); - return; // EARLY EXIT!!! - } - statement.close(); - } - catch( SQLException sqle ) { - log.debug( "Unable to release statement [" + sqle.getMessage() + "]" ); - } - } - - protected final void close(ResultSet resultSet) { - log.trace( "closing result set [" + resultSet + "]" ); - try { - resultSet.close(); - } - catch( SQLException e ) { - log.debug( "Unable to release result set [" + e.getMessage() + "]" ); - } - } - - public final void close() { - log.trace( "closing workspace [" + this + "]" ); - Iterator iter = registeredResultSets.iterator(); - while ( iter.hasNext() ) { - close( ( ResultSet ) iter.next() ); - } - registeredResultSets.clear(); - - iter = registeredStatements.iterator(); - while ( iter.hasNext() ) { - close( ( PreparedStatement ) iter.next() ); - } - registeredStatements.clear(); - - closed(); - } - } - - public class IsolatedWorkspaceImpl extends AbstractWorkspaceImpl implements Workspace { - private Connection connection; - public Connection getConnection() { - return connection; - } - - public void prepare() { - try { - connection = connectionProvider.getConnection(); - log.debug( "obtained JDBC connection for isolated work" ); - if ( stats != null ) { - stats.connect(); - } - } - catch( SQLException sqle ) { - throw convert( sqle, "Unable to obtain JDBC connection for isolated work" ); - } - } - - public void release() { - try { - connectionProvider.closeConnection( connection ); - log.debug( "released JDBC connection for isolated work" ); - } - catch( SQLException sqle ) { - log.trace( "unable to release connection on exception [" + sqle + "]" ); - } - finally { - connection = null; - } - } - } - - public class WorkspaceImpl extends AbstractWorkspaceImpl implements Workspace { - public Connection getConnection() { return JDBCContainerImpl.this.getLogicalConnection().getConnection(); } Added: trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/JDBCContainerImplementor.java =================================================================== --- trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/JDBCContainerImplementor.java 2006-01-17 12:14:24 UTC (rev 2122) +++ trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/jdbc3/impl/JDBCContainerImplementor.java 2006-01-17 15:06:53 UTC (rev 2123) @@ -0,0 +1,23 @@ +package org.hibernate.jdbc3.impl; + +import org.hibernate.jdbc3.JDBCContainer; +import org.hibernate.jdbc3.util.SQLStatementLogger; +import org.hibernate.dialect.Dialect; +import org.hibernate.connection.ConnectionProvider; +import org.hibernate.stat.StatisticsImplementor; +import org.hibernate.JDBCException; + +import java.sql.SQLException; + +/** + * @author Steve Ebersole + */ +public interface JDBCContainerImplementor extends JDBCContainer { + public Dialect getDialect(); + public SQLStatementLogger getStatementLogger(); + public ConnectionProvider getConnectionProvider(); + public StatisticsImplementor getStatistics(); + + public JDBCException convert(SQLException sqle, String message); + public JDBCException convert(SQLException sqle, String message, String sql); +} Modified: trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/IsolationDelegate.java =================================================================== --- trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/IsolationDelegate.java 2006-01-17 12:14:24 UTC (rev 2122) +++ trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/IsolationDelegate.java 2006-01-17 15:06:53 UTC (rev 2123) @@ -1,11 +1,11 @@ package org.hibernate.tx; import org.hibernate.jdbc3.Work; -import org.hibernate.jdbc3.impl.JDBCContainerImpl; +import org.hibernate.jdbc3.impl.JDBCContainerImplementor; /** * @author Steve Ebersole */ public interface IsolationDelegate { - public void doWorkInIsolation(Work work, JDBCContainerImpl.IsolatedWorkspaceImpl workspace); + public void doWorkInIsolation(Work work, JDBCContainerImplementor container); } Added: trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/IsolatedWorkspace.java =================================================================== --- trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/IsolatedWorkspace.java 2006-01-17 12:14:24 UTC (rev 2122) +++ trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/IsolatedWorkspace.java 2006-01-17 15:06:53 UTC (rev 2123) @@ -0,0 +1,22 @@ +package org.hibernate.tx.impl; + +import org.hibernate.jdbc3.impl.AbstractWorkspace; +import org.hibernate.jdbc3.impl.JDBCContainerImplementor; + +import java.sql.Connection; + +/** + * @author Steve Ebersole + */ +public class IsolatedWorkspace extends AbstractWorkspace { + private final Connection connection; + + public IsolatedWorkspace(JDBCContainerImplementor container, Connection connection) { + super( container ); + this.connection = connection; + } + + public Connection getConnection() { + return connection; + } +} Added: trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/JDBCIsolationDelegate.java =================================================================== --- trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/JDBCIsolationDelegate.java 2006-01-17 12:14:24 UTC (rev 2122) +++ trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/JDBCIsolationDelegate.java 2006-01-17 15:06:53 UTC (rev 2123) @@ -0,0 +1,77 @@ +package org.hibernate.tx.impl; + +import org.hibernate.tx.IsolationDelegate; +import org.hibernate.jdbc3.Work; +import org.hibernate.jdbc3.impl.JDBCContainerImplementor; +import org.hibernate.HibernateException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * @author Steve Ebersole + */ +public class JDBCIsolationDelegate implements IsolationDelegate { + + private static final Log log = LogFactory.getLog( JDBCIsolationDelegate.class ); + + public void doWorkInIsolation(Work work, JDBCContainerImplementor container) { + Connection connection = null; + boolean wasAutoCommit = false; + try { + connection = container.getConnectionProvider().getConnection(); + if ( connection.getAutoCommit() ) { + wasAutoCommit = true; + connection.setAutoCommit( false ); + } + + IsolatedWorkspace workspace = new IsolatedWorkspace( container, connection ); + try { + work.performWork( workspace ); + } + finally { + workspace.close(); + } + + connection.commit(); + } + catch( Throwable t ) { + try { + if ( connection!= null && !connection.isClosed() ) { + connection.rollback(); + } + } + catch( Throwable ignore ) { + log.trace( "unable to release connection on exception [" + ignore + "]" ); + } + + if ( t instanceof HibernateException ) { + throw ( HibernateException ) t; + } + else if ( t instanceof SQLException ) { + throw container.convert( ( SQLException ) t, "error performing isolated work" ); + } + else { + throw new HibernateException( "error performing isolated work", t ); + } + } + finally { + if ( wasAutoCommit ) { + try { + connection.setAutoCommit( true ); + } + catch( Throwable ignore ) { + log.trace( "was unable to reset connection back to auto-commit" ); + } + } + try { + container.getConnectionProvider().closeConnection( connection ); + } + catch( Throwable ignore ) { + log.info( "unable to release connection obtained for isolated work : " + ignore ); + } + } + } +} Added: trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/JTAIsolationDelegate.java =================================================================== --- trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/JTAIsolationDelegate.java 2006-01-17 12:14:24 UTC (rev 2122) +++ trunk/labs/hibernate/jdbc-redesign/src/org/hibernate/tx/impl/JTAIsolationDelegate.java 2006-01-17 15:06:53 UTC (rev 2123) @@ -0,0 +1,101 @@ +package org.hibernate.tx.impl; + +import org.hibernate.tx.IsolationDelegate; +import org.hibernate.jdbc3.Work; +import org.hibernate.jdbc3.impl.JDBCContainerImplementor; +import org.hibernate.HibernateException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.transaction.TransactionManager; +import javax.transaction.Transaction; +import java.sql.Connection; + +/** + * @author Steve Ebersole + */ +public class JTAIsolationDelegate implements IsolationDelegate { + + private static final Log log = LogFactory.getLog( JTAIsolationDelegate.class ); + + private final TransactionManager transactionManager; + + public JTAIsolationDelegate(TransactionManager transactionManager) { + this.transactionManager = transactionManager; + } + + public void doWorkInIsolation(Work work, JDBCContainerImplementor container) { + Transaction surroundingTransaction = null; + Connection connection = null; + boolean caughtException = false; + + try { + // First we need to suspend any current JTA transaction and obtain + // a JDBC connection + surroundingTransaction = transactionManager.suspend(); + if ( log.isDebugEnabled() ) { + log.debug( "surrounding JTA transaction suspended [" + surroundingTransaction + "]" ); + } + transactionManager.begin(); + connection = container.getConnectionProvider().getConnection(); + + // perform the actual work + IsolatedWorkspace workspace = new IsolatedWorkspace( container, connection ); + try { + work.performWork( workspace ); + } + finally { + workspace.close(); + } + + // if everything went ok, commit the transaction and close the obtained + // connection handle... + container.getConnectionProvider().closeConnection( connection ); + transactionManager.commit(); + } + catch( Throwable t ) { + // at some point the processing went bad, so we need to: + // 1) make sure the connection handle gets released + // 2) try to cleanup the JTA context as much as possible + caughtException = true; + try { + if ( connection != null && !connection.isClosed() ) { + container.getConnectionProvider().closeConnection( connection ); + } + } + catch( Throwable ignore ) { + log.trace( "unable to release connection on exception [" + ignore + "]" ); + } + try { + transactionManager.rollback(); + } + catch( Throwable ignore ) { + log.trace( "unable to rollback new transaction on exception [" + ignore + "]" ); + } + + // finally handle the exception + if ( t instanceof HibernateException ) { + throw ( HibernateException ) t; + } + else { + throw new HibernateException( "error performing isolated work", t ); + } + } + finally { + if ( surroundingTransaction != null ) { + try { + transactionManager.resume( surroundingTransaction ); + if ( log.isDebugEnabled() ) { + log.debug( "surrounding JTA transaction resumed [" + surroundingTransaction + "]" ); + } + } + catch( Throwable t ) { + if ( !caughtException ) { + new HibernateException( "unable to resume previously suspended transaction", t ); + } + } + } + } + } + +} |