[hibernate-commits] Hibernate SVN: r10304 - in trunk/sandbox/jdbc: . src src/main src/main/java src/main/java/org src/main/java/org/hibernate src/main/java/org/hibernate/jdbc4 src/main/java/org/hibernate/jdbc4/jdbc src/main/java/org/hibernate/jdbc4/jdbc/command src/main/java/org/hibernate/jdbc4/jdbc/impl src/main/java/org/hibernate/jdbc4/jdbc/util src/main/java/org/hibernate/jdbc4/tx src/main/java/org/hibernate/jdbc4/tx/impl src/test src/test/java src/test/java/org src/test/java/org/hibernate src/test/java/org/hibernate/jdbc4 src/test/java/org/hibernate/jdbc4/domain src/test/java/org/hibernate/jdbc4/jdbc src/test/java/org/hibernate/jdbc4/jdbc/command src/test/java/org/hibernate/jdbc4/jdbc/impl src/test/java/org/hibernate/jdbc4/tx src/test/resources

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Mon Aug 21 13:21:54 EDT 2006


Author: steve.ebersole at jboss.com
Date: 2006-08-21 13:21:49 -0400 (Mon, 21 Aug 2006)
New Revision: 10304

Added:
   trunk/sandbox/jdbc/src/
   trunk/sandbox/jdbc/src/main/
   trunk/sandbox/jdbc/src/main/java/
   trunk/sandbox/jdbc/src/main/java/org/
   trunk/sandbox/jdbc/src/main/java/org/hibernate/
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/Settings.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/Transaction.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/JDBCContainer.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/LogicalConnection.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/LogicalConnectionBuilder.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/Work.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/Workspace.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/AbstractCommand.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand2.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand2Impl.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommandImpl.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/Executor.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ParameterBinds.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/QueryCommand.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/QueryCommandImpl.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ResultSetProcessor.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/StatementCreator.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/StatementOptions.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/AbstractWorkspace.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/JDBCContainerImpl.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/JDBCContainerImplementor.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/util/
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/util/SQLStatementLogger.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/IsolationDelegate.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/Listener.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/TransactionCoordinator.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/TransactionFactory.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/AbstractTransactionImpl.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/IsolatedWorkspace.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCIsolationDelegate.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCTransaction.java
   trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCTransactionFactory.java
   trunk/sandbox/jdbc/src/test/
   trunk/sandbox/jdbc/src/test/java/
   trunk/sandbox/jdbc/src/test/java/org/
   trunk/sandbox/jdbc/src/test/java/org/hibernate/
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/JournalingTransactionListener.java
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/LogicalConnectionObserver.java
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/LineItem.hbm.xml
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/LineItem.java
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Order.hbm.xml
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Order.java
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Product.hbm.xml
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Product.java
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/AbstractTestCase.java
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/command/
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/command/BasicCommandTest.java
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/command/BasicPersisterUsageTest.java
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/impl/
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/impl/BasicWorkTest.java
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/tx/
   trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/tx/BasicTransactionCoordinatorTest.java
   trunk/sandbox/jdbc/src/test/resources/
   trunk/sandbox/jdbc/src/test/resources/hibernate.properties
   trunk/sandbox/jdbc/src/test/resources/log4j.properties
Log:
added jdbc redesign stuff to sandbox

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/Settings.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/Settings.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/Settings.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,93 @@
+package org.hibernate.jdbc4;
+
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.jdbc4.tx.TransactionFactory;
+import org.hibernate.jdbc4.tx.impl.JDBCTransactionFactory;
+import org.hibernate.jdbc4.jdbc.util.SQLStatementLogger;
+import org.hibernate.jdbc4.jdbc.LogicalConnectionBuilder;
+import org.hibernate.jdbc4.jdbc.LogicalConnection;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.connection.ConnectionProviderFactory;
+import org.hibernate.stat.StatisticsImpl;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Mimics {@link org.hibernate.cfg.Settings} for the purpose of adding
+ * new settings that would be useful in this setup...
+ *
+ * @author Steve Ebersole
+ */
+public class Settings {
+	private Dialect dialect = Dialect.getDialect();
+	private SQLExceptionConverter exceptionConverter = dialect.buildSQLExceptionConverter();
+	private TransactionFactory transactionFactory = new JDBCTransactionFactory();
+	private ConnectionProvider connectionProvider = ConnectionProviderFactory.newConnectionProvider();
+	private ConnectionReleaseMode connectionReleaseMode = ConnectionReleaseMode.AFTER_TRANSACTION;
+
+
+	// explicitly new stuff ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	private SQLStatementLogger sqlStatementLogger = new SQLStatementLogger( true );
+	private StatisticsImpl statistics = new StatisticsImpl(); // specifically, moved here...
+
+
+	// accessors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public SQLExceptionConverter getExceptionConverter() {
+		return exceptionConverter;
+	}
+
+	public void setExceptionConverter(SQLExceptionConverter exceptionConverter) {
+		this.exceptionConverter = exceptionConverter;
+	}
+
+	public TransactionFactory getTransactionFactory() {
+		return transactionFactory;
+	}
+
+	public void setTransactionFactory(TransactionFactory transactionFactory) {
+		this.transactionFactory = transactionFactory;
+	}
+
+	public ConnectionProvider getConnectionProvider() {
+		return connectionProvider;
+	}
+
+	public void setConnectionProvider(ConnectionProvider connectionProvider) {
+		this.connectionProvider = connectionProvider;
+	}
+
+	public SQLStatementLogger getSqlStatementLogger() {
+		return sqlStatementLogger;
+	}
+
+	public void setSqlStatementLogger(SQLStatementLogger sqlStatementLogger) {
+		this.sqlStatementLogger = sqlStatementLogger;
+	}
+
+	public StatisticsImpl getStatistics() {
+		return statistics;
+	}
+
+	public void setStatisticsImplementor(StatisticsImpl statistics) {
+		this.statistics = statistics;
+	}
+
+	public ConnectionReleaseMode getConnectionReleaseMode() {
+		return connectionReleaseMode;
+	}
+
+	public void setConnectionReleaseMode(ConnectionReleaseMode connectionReleaseMode) {
+		this.connectionReleaseMode = connectionReleaseMode;
+	}
+
+	public Dialect getDialect() {
+		return dialect;
+	}
+
+	public void setDialect(Dialect dialect) {
+		this.dialect = dialect;
+	}
+
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/Transaction.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/Transaction.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/Transaction.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,96 @@
+package org.hibernate.jdbc4;
+
+import org.hibernate.HibernateException;
+
+import javax.transaction.Synchronization;
+
+/**
+ * Defines Hibernate's notion of a logical or conceptual transaction.
+ * <p/>
+ * Allows the application to define units of work, while maintaining abstraction
+ * from the underlying transaction implementation (eg. JTA, JDBC)
+ *
+ * @author Anton van Straaten
+ * @author Steve Ebersole
+ */
+public interface Transaction {
+
+	/**
+	 * Begin a new transaction.
+	 */
+	public void begin() throws HibernateException;
+
+	/**
+	 * Flush the associated {@link org.hibernate.Session} (unless we are in
+	 * {@link org.hibernate.FlushMode#NEVER}) and end the unit of work.
+	 * </p>
+	 * This method will commit the underlying transaction if and only
+	 * if the underlying transaction was initiated by this object.
+	 *
+	 * @throws HibernateException
+	 */
+	public void commit() throws HibernateException;
+
+	/**
+	 * Force the underlying transaction to roll back.
+	 *
+	 * @throws HibernateException
+	 */
+	public void rollback() throws HibernateException;
+
+	/**
+	 * Was this transaction rolled back or set to rollback only?
+	 * <p/>
+	 * This only accounts for actions initiated from this local transaction.
+	 * If, for example, the underlying transaction is forced to rollback via
+	 * some other means, this method still reports false because the rollback
+	 * was not initiated from here.
+	 *
+	 * @return boolean True if the transaction was rolled back via this
+	 * local transaction; false otherwise.
+	 * @throws HibernateException
+	 */
+	public boolean wasRolledBack() throws HibernateException;
+
+	/**
+	 * Check if this transaction was successfully committed.
+	 * <p/>
+	 * This method could return <tt>false</tt> even after successful invocation
+	 * of {@link #commit}.  As an example, JTA based strategies no-op on
+	 * {@link #commit} calls if they did not start the transaction; in that case,
+	 * they also report {@link #wasCommitted} as false.
+	 *
+	 * @return boolean True if the transaction was (unequivocally) committed
+	 * via this local transaction; false otherwise.
+	 * @throws HibernateException
+	 */
+	public boolean wasCommitted() throws HibernateException;
+
+	/**
+	 * Is this transaction still active?
+	 * <p/>
+	 * Again, this only returns information in relation to the
+	 * local transaction, not the actual underlying transaction.
+	 *
+	 * @return boolean Treu if this local transaction is still active.
+	 */
+	public boolean isActive() throws HibernateException;
+
+	/**
+	 * Register a user synchronization callback for this transaction.
+	 *
+	 * @param synchronization The Synchronization callback to register.
+	 * @throws HibernateException
+	 */
+	public void registerSynchronization(Synchronization synchronization) throws HibernateException;
+
+	/**
+	 * Set the transaction timeout for any transaction started by
+	 * a subsequent call to <tt>begin()</tt> on this instance.
+	 *
+	 * @param seconds The number of seconds before a timeout.
+	 */
+	public void setTimeout(int seconds);
+
+	public int getTimeout();
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/JDBCContainer.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/JDBCContainer.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/JDBCContainer.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,59 @@
+package org.hibernate.jdbc4.jdbc;
+
+import org.hibernate.HibernateException;
+
+import java.sql.Connection;
+
+/**
+ * Represents a container for performing all JDBC-related work.
+ *
+ * @author Steve Ebersole
+ */
+public interface JDBCContainer {
+
+	/**
+	 * Performs some work within the confines of this container.
+	 *
+	 * @param work The work to be performed.
+	 * @throws HibernateException Indicates a problem occurred trying to
+	 * perform the requested work.
+	 */
+	public void doWork(Work work) throws HibernateException;
+
+	/**
+	 * Performs some work within the confines of this container.
+	 *
+	 * @param work The work to be performed.
+	 * @throws HibernateException Indicates a problem occurred trying to
+	 * perform the requested work.
+	 */
+	public void doWorkInSeperateTransaction(Work work) throws HibernateException;
+
+	/**
+	 * Cancels the last requested operation.
+	 *
+	 * @throws HibernateException Indicates a problem cancelling the last
+	 * operation.
+	 */
+	public void cancelLastQuery() throws HibernateException;
+
+//	public void doBatch(String sql, StatementCreator creator, StatementOptions options, ParameterBinds binds, int expectedRowCount)
+//			throws JDBCException, HibernateException;
+
+	/**
+	 * Allows direct access to the underlying JDBC connection.
+	 * <p/>
+	 * This is here (though deprecated) for legacy purposes.
+	 *
+	 * @return The underlying JDBC connection
+	 * @deprecated use {@link #doWork(Work)} instead.
+	 */
+	public Connection borrowConnection();
+
+	/**
+	 * Closes this container.
+	 *
+	 * @return The connection if the connection was user-supplied; null otherwise.
+	 */
+	public Connection close();
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/LogicalConnection.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/LogicalConnection.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/LogicalConnection.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,202 @@
+package org.hibernate.jdbc4.jdbc;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.exception.SQLExceptionConverter;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.HibernateException;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.JDBCException;
+import org.hibernate.jdbc4.jdbc.util.SQLStatementLogger;
+import org.hibernate.util.JDBCExceptionReporter;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * Defines a "logical connection" which encapsulates and hides functionality
+ * such as the aggressive releasing and subsequent acquisition of JDBC
+ * connections.
+ *
+ * @author Steve Ebersole
+ */
+public class LogicalConnection {
+	private static final Log log = LogFactory.getLog( LogicalConnection.class );
+
+	public static interface Observer {
+		public void connectionObtained();
+		public void connectionReleased();
+	}
+
+	private transient Connection connection;
+	private final ConnectionProvider connectionProvider;
+	private final ConnectionReleaseMode connectionReleaseMode;
+	private final SQLExceptionConverter exceptionConverter;
+	private final SQLStatementLogger sqlStatementLogger;
+	private final Observer observer;
+
+	private final boolean isUserSuppliedConnection;
+
+	private boolean isClosed;
+
+	public LogicalConnection(
+	        Connection userSuppliedConnection,
+	        ConnectionProvider connectionProvider,
+	        ConnectionReleaseMode connectionReleaseMode,
+	        SQLExceptionConverter exceptionConverter,
+	        SQLStatementLogger sqlStatementLogger,
+	        Observer observer) {
+		this.connection = userSuppliedConnection;
+		this.connectionProvider = connectionProvider;
+		this.connectionReleaseMode = connectionReleaseMode;
+		this.exceptionConverter = exceptionConverter;
+		this.sqlStatementLogger = sqlStatementLogger;
+		this.observer = observer == null ? new NoObserver() : observer;
+
+		isUserSuppliedConnection = ( userSuppliedConnection != null );
+	}
+
+	public ConnectionReleaseMode getConnectionReleaseMode() {
+		return connectionReleaseMode;
+	}
+
+	public SQLStatementLogger getStatementLogger() {
+		return sqlStatementLogger;
+	}
+
+	public ConnectionProvider getConnectionProvider() {
+		return connectionProvider;
+	}
+
+	public JDBCException convert(SQLException sqle, String message) {
+		return JDBCExceptionHelper.convert( exceptionConverter, sqle, message );
+	}
+
+	public JDBCException convert(SQLException sqle, String message, String sql) {
+		return JDBCExceptionHelper.convert( exceptionConverter, sqle, message, sql );
+	}
+
+
+	/**
+	 * Is this LogicalConnection instance "physically" connection.  Meaning
+	 * do have currently actually have a cached connection.
+	 *
+	 * @return True if physically connected; false otherwise.
+	 */
+	public boolean isPhysicallyConnected() {
+		return connection != null;
+	}
+
+	/**
+	 * Retreives the connection currently "logically" managed by this LogicalConnection.
+	 * <p/>
+	 * 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.
+	 *
+	 * @return The current Connection.
+	 *
+	 * @throws HibernateException Indicates a connection is currently not
+	 * available (we are currently manually disconnected).
+	 */
+	public Connection getConnection() throws HibernateException {
+		if ( isClosed ) {
+			throw new HibernateException( "Logical connection is closed" );
+		}
+		if ( connection == null ) {
+			if ( isUserSuppliedConnection ) {
+				// should never happen
+				throw new HibernateException( "User-supplied connection was null" );
+			}
+			obtainConnection();
+		}
+		return connection;
+	}
+
+	/**
+	 * 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.
+	 */
+	public boolean isAutoCommit() throws SQLException {
+		return connection == null || connection.getAutoCommit();
+	}
+
+	/**
+	 * Force aggresive release of the underlying connection.
+	 */
+	public void aggressiveRelease() {
+		if ( !isUserSuppliedConnection ) {
+			log.debug( "aggressively releasing JDBC connection" );
+			if ( connection != null ) {
+				releaseConnection();
+			}
+		}
+	}
+
+	/**
+	 * Release the underlying connection and clean up any other resources associated
+	 * with this logical connection.
+	 * <p/>
+	 * This leaves the logical connection in a "no longer useable" state.
+	 */
+	public Connection close() {
+		Connection c = connection;
+		if ( !isUserSuppliedConnection && connection != null ) {
+			releaseConnection();
+		}
+		// not matter what
+		connection = null;
+		isClosed = true;
+		return c;
+	}
+
+	/**
+	 * Pysically opens a JDBC Connection.
+	 *
+	 * @throws org.hibernate.HibernateException
+	 */
+	private void obtainConnection() throws HibernateException {
+		log.debug( "obtaining JDBC connection" );
+		try {
+			connection = connectionProvider.getConnection();
+			observer.connectionObtained();
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert( exceptionConverter, sqle, "Cannot open connection" );
+		}
+		log.debug( "obtained JDBC connection" );
+	}
+
+	/**
+	 * Physically closes the JDBC Connection.
+	 */
+	private void releaseConnection() {
+		log.debug( "releasing JDBC connection" );
+		try {
+			if ( !connection.isClosed() ) {
+				JDBCExceptionReporter.logAndClearWarnings( connection );
+			}
+			connectionProvider.closeConnection( connection );
+			connection = null;
+			observer.connectionReleased();
+		}
+		catch (SQLException sqle) {
+			throw JDBCExceptionHelper.convert( exceptionConverter, sqle, "Cannot close connection" );
+		}
+		log.debug( "released JDBC connection" );
+	}
+
+	private static class NoObserver implements Observer {
+		public void connectionObtained() {
+			//To change body of implemented methods use File | Settings | File Templates.
+		}
+		public void connectionReleased() {
+			//To change body of implemented methods use File | Settings | File Templates.
+		}
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/LogicalConnectionBuilder.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/LogicalConnectionBuilder.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/LogicalConnectionBuilder.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,31 @@
+package org.hibernate.jdbc4.jdbc;
+
+import org.hibernate.jdbc4.Settings;
+
+import java.sql.Connection;
+
+/**
+ * todo: describe LogicalConnectionBuilder
+ *
+ * @author Steve Ebersole
+ */
+public class LogicalConnectionBuilder {
+	private final Settings settings;
+	private final LogicalConnection.Observer observer;
+
+	public LogicalConnectionBuilder(Settings settings, LogicalConnection.Observer observer) {
+		this.settings = settings;
+		this.observer = observer;
+	}
+
+	public synchronized LogicalConnection buiLogicalConnection(Connection userSuppliedConnection) {
+		return new LogicalConnection(
+				userSuppliedConnection,
+				settings.getConnectionProvider(),
+		        settings.getConnectionReleaseMode(),
+				settings.getExceptionConverter(),
+		        settings.getSqlStatementLogger(),
+				observer
+		);
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/Work.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/Work.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/Work.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,44 @@
+package org.hibernate.jdbc4.jdbc;
+
+import org.hibernate.HibernateException;
+
+import java.sql.SQLException;
+
+/**
+ * Represents an interaction (or series of interactions) with JDBC.
+ *
+ * @author Steve Ebersole
+ */
+public interface Work {
+	/**
+	 * Perform the encapsulated work, using the given JDBC workspace.
+	 *
+	 * @param workspace The JDBC workspace in which to execute this work.
+	 *
+	 * @throws SQLException The preferred approach is to throw HibernateExceptions
+	 * rather than SQLExceptions since more contextual information is available
+	 * to the work itself in all likelihood.
+	 * @throws HibernateException
+	 */
+	public void performWork(Workspace workspace) throws SQLException, HibernateException;
+
+	/**
+	 * Are the resources obtained by this work concise?  Meaning can all the
+	 * JDBC resources obtained by this work be released after execution of the
+	 * work.
+	 *
+	 * @return True if the work is concise and resources can be immediately
+	 * released after work execution; false otherwise.
+	 */
+	public boolean isConcise();
+
+//	/**
+//	 * Used to request cancellation of the last operation.
+//	 *
+//	 * @throws SQLException The preferred approach is to throw HibernateExceptions
+//	 * rather than SQLExceptions since more contextual information is available
+//	 * to the work itself in all likelihood.
+//	 * @throws HibernateException
+//	 */
+//	public void cancel() throws SQLException, HibernateException;
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/Workspace.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/Workspace.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/Workspace.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,95 @@
+package org.hibernate.jdbc4.jdbc;
+
+import org.hibernate.JDBCException;
+import org.hibernate.jdbc4.jdbc.util.SQLStatementLogger;
+import org.hibernate.dialect.Dialect;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+
+/**
+ * Defines a "workspace" in which {@link Work JDBC work} occurs.
+ * <p/>
+ * The most important aspects to a workspace are:<ul>
+ * <li>access to a JDBC connection ({@link #getConnection})
+ * <li>registration of JDBC resources for automatic cleanup
+ * ({@link #register(java.sql.PreparedStatement)} and {@link #register(java.sql.ResultSet)})
+ * </ul>
+ * The rest of the exposed functionality is for convenience purposes.
+ *
+ * @author Steve Ebersole
+ */
+public interface Workspace {
+	/**
+	 * Retreives the connection in effect for this workspace.
+	 *
+	 * @return The JDBC connection.
+	 */
+	public Connection getConnection();
+
+	/**
+	 * The dialect for the underlying database.
+	 *
+	 * @return The dialect.
+	 */
+	public  Dialect getDialect();
+
+	/**
+	 * Registers the prepared statement with the workspace for cleanup
+	 * purposes.
+	 *
+	 * @param statement The prepared statement to register.
+	 */
+	public void register(PreparedStatement statement);
+
+	/**
+	 * Used to manually release the given prepared statement.
+	 *
+	 * @param statement The prepared statement to release.
+	 */
+	public void release(PreparedStatement statement);
+
+	/**
+	 * Registers the result set with the workspace for cleanup purposes.
+	 *
+	 * @param resultSet The result set to register.
+	 */
+	public void register(ResultSet resultSet);
+
+	/**
+	 * Used to manually release the given result set.
+	 *
+	 * @param resultSet The result set to release.
+	 */
+	public void release(ResultSet resultSet);
+
+	/**
+	 * Convenience access to the SQL statement logger.
+	 *
+	 * @return The SQL statement logger.
+	 */
+	public SQLStatementLogger getSqlLogger();
+
+	/**
+	 * Convenience access to SQLException conversion.
+	 *
+	 * @param sqlException The SQLException.
+	 * @param message The message to use for the converted JDBCException.
+	 *
+	 * @return The converted JDBCException.
+	 */
+	public JDBCException convert(SQLException sqlException, String message);
+
+	/**
+	 * Convenience access to SQLException conversion.
+	 *
+	 * @param sqlException The SQLException.
+	 * @param message The message to use for the converted JDBCException.
+	 * @param sql The SQL statement which resulted in the given SQLException
+	 *
+	 * @return The converted JDBCException.
+	 */
+	public JDBCException convert(SQLException sqlException, String message, String sql);
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/AbstractCommand.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/AbstractCommand.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/AbstractCommand.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,52 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.jdbc4.jdbc.Work;
+
+import java.sql.PreparedStatement;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * @author Steve Ebersole
+ */
+public abstract class AbstractCommand {
+
+	protected final String sql;
+	protected final StatementCreator creator;
+	protected final StatementOptions options;
+	protected final boolean concise;
+
+	protected AbstractCommand(String sql, StatementCreator creator) {
+		this( sql, creator, null );
+	}
+
+	protected AbstractCommand(String sql, StatementCreator creator, StatementOptions options) {
+		this( sql, creator, options, false );
+	}
+
+	protected AbstractCommand(String sql, StatementCreator creator, boolean concise) {
+		this( sql, creator, null, concise );
+	}
+
+	public AbstractCommand(String sql, StatementCreator creator, StatementOptions options, boolean concise) {
+		this.sql = sql;
+		this.creator = creator;
+		this.options = options;
+		this.concise = concise;
+	}
+
+	protected abstract class WorkDelegate implements Work {
+		public final boolean isConcise() {
+			return AbstractCommand.this.concise;
+		}
+	}
+
+	public static class BasicCreator implements StatementCreator {
+		public PreparedStatement createPreparedStatement(Connection connection, String sql) throws SQLException {
+			return connection.prepareStatement( sql );
+		}
+		public boolean isStatementCallable() {
+			return false;
+		}
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,14 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.HibernateException;
+import org.hibernate.jdbc4.jdbc.JDBCContainer;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface ExecutionCommand {
+	public void execute(JDBCContainer container, ParameterBinds binds, Executor executor) throws HibernateException;
+	public void execute(JDBCContainer container, ParameterBinds binds) throws HibernateException;
+	public void execute(JDBCContainer container, Executor executor) throws HibernateException;
+	public void execute(JDBCContainer container) throws HibernateException;
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand2.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand2.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand2.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,13 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.jdbc4.jdbc.JDBCContainer;
+import org.hibernate.HibernateException;
+
+/**
+ * todo: describe ExecutionCommand2
+ *
+ * @author Steve Ebersole
+ */
+public interface ExecutionCommand2 {
+	public void execute(JDBCContainer container) throws HibernateException;
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand2Impl.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand2Impl.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommand2Impl.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,62 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.jdbc4.jdbc.JDBCContainer;
+import org.hibernate.jdbc4.jdbc.Work;
+import org.hibernate.jdbc4.jdbc.Workspace;
+import org.hibernate.HibernateException;
+
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.Connection;
+
+/**
+ * todo: describe ExecutionCommand2Impl
+ *
+ * @author Steve Ebersole
+ */
+public class ExecutionCommand2Impl implements ExecutionCommand2, Work {
+	private final String sql;
+
+	protected ExecutionCommand2Impl(String sql) {
+		this.sql = sql;
+	}
+
+	public void execute(JDBCContainer container) throws HibernateException {
+		container.doWork( this );
+	}
+
+	protected PreparedStatement createPreparedStatement(String sql, Connection connection) throws SQLException {
+		return connection.prepareStatement( sql );
+	}
+
+	protected void applyOptions(PreparedStatement statement) throws SQLException {
+	}
+
+	protected void bindParameterValues(PreparedStatement statement) throws SQLException {
+	}
+
+	protected void execute(PreparedStatement statement) throws SQLException {
+		statement.executeUpdate();
+	}
+
+
+	// Work implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void performWork(Workspace workspace) throws SQLException, HibernateException {
+		try {
+			workspace.getSqlLogger().logStatement( sql );
+			PreparedStatement stmnt = createPreparedStatement( sql, workspace.getConnection() );
+			workspace.register( stmnt );
+			applyOptions( stmnt );
+			bindParameterValues( stmnt );
+			execute( stmnt );
+		}
+		catch( SQLException sqle ) {
+			throw workspace.convert( sqle, "Unable to perform statement execution", sql );
+		}
+	}
+
+	public boolean isConcise() {
+		return true;
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommandImpl.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommandImpl.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ExecutionCommandImpl.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,85 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.HibernateException;
+import org.hibernate.jdbc4.jdbc.JDBCContainer;
+import org.hibernate.jdbc4.jdbc.Work;
+import org.hibernate.jdbc4.jdbc.Workspace;
+
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+
+/**
+ * @author Steve Ebersole
+ */
+public class ExecutionCommandImpl extends AbstractCommand implements ExecutionCommand {
+
+	public ExecutionCommandImpl(String sql) {
+		super( sql, new BasicCreator() );
+	}
+
+	public ExecutionCommandImpl(String sql, StatementCreator creator) {
+		super( sql, creator );
+	}
+
+	public ExecutionCommandImpl(String sql, StatementOptions options) {
+		super( sql, new BasicCreator(), options, true );
+	}
+
+	public ExecutionCommandImpl(String sql, StatementCreator creator, StatementOptions options) {
+		super( sql, creator, options, true );
+	}
+
+
+	// ExecutionCommand impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void execute(JDBCContainer container, ParameterBinds binds, Executor executor)
+			throws HibernateException {
+		container.doWork( new ExecutionWorkDelegate( binds, executor ) );
+	}
+
+	public void execute(JDBCContainer container, ParameterBinds binds) throws HibernateException {
+		execute( container, binds, new BasicExecutor() );
+	}
+
+	public void execute(JDBCContainer container, Executor executor) throws HibernateException {
+		execute( container, null, executor );
+	}
+
+	public void execute(JDBCContainer container) throws HibernateException {
+		execute( container, ( ParameterBinds ) null );
+	}
+
+	private class ExecutionWorkDelegate extends WorkDelegate implements Work {
+		private final ParameterBinds binds;
+		private final Executor executor;
+
+		public ExecutionWorkDelegate(ParameterBinds binds, Executor executor) {
+			this.binds = binds;
+			this.executor = executor;
+		}
+
+		public void performWork(Workspace workspace) throws SQLException, HibernateException {
+			try {
+				workspace.getSqlLogger().logStatement( sql );
+				PreparedStatement stmnt = creator.createPreparedStatement( workspace.getConnection(), sql );
+				workspace.register( stmnt );
+				if ( options != null ) {
+					options.apply( stmnt );
+				}
+				if ( binds != null ) {
+					binds.bindParameterValues( stmnt );
+				}
+				executor.execute( stmnt, workspace );
+			}
+			catch( SQLException sqle ) {
+				throw workspace.convert( sqle, "Unable to perform statement execution", sql );
+			}
+		}
+	}
+
+	public static class BasicExecutor implements Executor {
+		public void execute(PreparedStatement statement, Workspace workspace) throws SQLException, HibernateException {
+			statement.executeUpdate();
+		}
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/Executor.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/Executor.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/Executor.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,14 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.HibernateException;
+import org.hibernate.jdbc4.jdbc.Workspace;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface Executor {
+	public void execute(PreparedStatement statement, Workspace workspace) throws SQLException, HibernateException;
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ParameterBinds.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ParameterBinds.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ParameterBinds.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,13 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.HibernateException;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface ParameterBinds {
+	public void bindParameterValues(PreparedStatement stmnt) throws SQLException, HibernateException;
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/QueryCommand.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/QueryCommand.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/QueryCommand.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,12 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.HibernateException;
+import org.hibernate.jdbc4.jdbc.JDBCContainer;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface QueryCommand {
+	public void execute(JDBCContainer container, ParameterBinds binds, ResultSetProcessor processor) throws HibernateException;
+	public void execute(JDBCContainer container, ResultSetProcessor processor) throws HibernateException;
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/QueryCommandImpl.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/QueryCommandImpl.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/QueryCommandImpl.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,73 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.HibernateException;
+import org.hibernate.jdbc4.jdbc.JDBCContainer;
+import org.hibernate.jdbc4.jdbc.Work;
+import org.hibernate.jdbc4.jdbc.Workspace;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @author Steve Ebersole
+ */
+public class QueryCommandImpl extends AbstractCommand implements QueryCommand {
+	public QueryCommandImpl(String sql) {
+		super( sql, new BasicCreator() );
+	}
+
+	public QueryCommandImpl(String sql, StatementCreator creator) {
+		super( sql, creator );
+	}
+
+	public QueryCommandImpl(String sql, StatementCreator creator, StatementOptions options) {
+		super( sql, creator, options );
+	}
+
+	public QueryCommandImpl(String sql, StatementCreator creator, boolean concise) {
+		super( sql, creator, concise );
+	}
+
+	public QueryCommandImpl(String sql, StatementCreator creator, StatementOptions options, boolean concise) {
+		super( sql, creator, options, concise );
+	}
+
+	public void execute(JDBCContainer container, ParameterBinds binds, ResultSetProcessor processor) throws HibernateException {
+		container.doWork( new QueryWorkDelegate( binds, processor ) );
+	}
+
+	public void execute(JDBCContainer container, ResultSetProcessor processor) throws HibernateException {
+		execute( container, null, processor );
+	}
+
+	private class QueryWorkDelegate extends WorkDelegate implements Work {
+		private final ParameterBinds binds;
+		private final ResultSetProcessor processor;
+
+		public QueryWorkDelegate(ParameterBinds binds, ResultSetProcessor processor) {
+			this.binds = binds;
+			this.processor = processor;
+		}
+
+		public void performWork(Workspace workspace) throws HibernateException {
+			try {
+				workspace.getSqlLogger().logStatement( sql );
+				PreparedStatement stmnt = creator.createPreparedStatement( workspace.getConnection(), sql );
+				workspace.register( stmnt );
+				if ( options != null ) {
+					options.apply( stmnt );
+				}
+				if ( binds != null ) {
+					binds.bindParameterValues( stmnt );
+				}
+				ResultSet results = stmnt.executeQuery();
+				workspace.register( results );
+				processor.processResults( results );
+			}
+			catch( SQLException sqle ) {
+				throw workspace.convert( sqle, "Unable to perform query", sql );
+			}
+		}
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ResultSetProcessor.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ResultSetProcessor.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/ResultSetProcessor.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,13 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.HibernateException;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface ResultSetProcessor {
+	public void processResults(ResultSet results) throws SQLException, HibernateException;
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/StatementCreator.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/StatementCreator.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/StatementCreator.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,29 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import java.sql.PreparedStatement;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * Defines the contract for implementors knowing how to generate a
+ * {@link java.sql.PreparedStatement}.
+ * <p/>
+ * It is expected that implementors will fully complete the statement
+ * preparation process, including setting any additional statement
+ * specification parameters prior to returning the statement for use.
+ *
+ * @author Steve Ebersole
+ */
+public interface StatementCreator {
+	/**
+	 * Create a SQL PreparedStatement given the container and sql.
+	 *
+	 * @param connection The JDBC Connection on which to create the PreparedStatement
+	 * @param sql The SQL statement string to prepare.
+	 * @return The created PreparedStatement.
+	 * @throws java.sql.SQLException Indicates problems creating the PreparedStatement.
+	 */
+	public PreparedStatement createPreparedStatement(Connection connection, String sql) throws SQLException;
+
+	public boolean isStatementCallable();
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/StatementOptions.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/StatementOptions.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/command/StatementOptions.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,47 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+/**
+ * An immutable representation of {@link java.sql.PreparedStatement}
+ * preparation options.
+ *
+ * @author Steve Ebersole
+ */
+public class StatementOptions implements Serializable {
+	private final Integer timeout;
+	private final Integer fetchSize;
+	private final Integer maxRows;
+
+	public StatementOptions(Integer timeout, Integer fetchSize, Integer maxRows) {
+		this.timeout = timeout;
+		this.fetchSize = fetchSize;
+		this.maxRows = maxRows;
+	}
+
+	public Integer getTimeout() {
+		return timeout;
+	}
+
+	public Integer getFetchSize() {
+		return fetchSize;
+	}
+
+	public Integer getMaxRows() {
+		return maxRows;
+	}
+
+	public void apply(PreparedStatement stmnt) throws SQLException {
+		if ( timeout != null ) {
+			stmnt.setQueryTimeout( timeout.intValue() );
+		}
+		if ( fetchSize != null ) {
+			stmnt.setFetchSize( fetchSize.intValue() );
+		}
+		if ( maxRows != null ) {
+			stmnt.setMaxRows( maxRows.intValue() );
+		}
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/AbstractWorkspace.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/AbstractWorkspace.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/AbstractWorkspace.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,130 @@
+package org.hibernate.jdbc4.jdbc.impl;
+
+import org.hibernate.jdbc4.jdbc.Workspace;
+import org.hibernate.jdbc4.jdbc.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.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * todo: describe AbstractWorkspace
+ *
+ * @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();
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/JDBCContainerImpl.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/JDBCContainerImpl.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/JDBCContainerImpl.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,203 @@
+package org.hibernate.jdbc4.jdbc.impl;
+
+import org.hibernate.jdbc4.jdbc.JDBCContainer;
+import org.hibernate.jdbc4.jdbc.LogicalConnection;
+import org.hibernate.jdbc4.jdbc.Work;
+import org.hibernate.jdbc4.jdbc.Workspace;
+import org.hibernate.jdbc4.jdbc.util.SQLStatementLogger;
+import org.hibernate.jdbc4.tx.IsolationDelegate;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.HibernateException;
+import org.hibernate.JDBCException;
+import org.hibernate.stat.StatisticsImplementor;
+import org.hibernate.dialect.Dialect;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.HashMap;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+
+/**
+ * @author Steve Ebersole
+ */
+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
+	//      higher level.  For example, consider the flush() use-case; would be great
+	//      to have the workspace lifecycle tied to the flush lifecycle to avoid
+	//      spurious aggressive connection releases.
+
+	public static interface TransactionIsolationDelegateBuilder {
+		public IsolationDelegate buildIsolationDelegate();
+	}
+
+	private static final Log log = LogFactory.getLog( JDBCContainerImpl.class );
+
+	private Map workMap = new HashMap();
+
+//	private PreparedStatement lastQuery;
+
+	private final LogicalConnection logicalConnection;
+	private final TransactionIsolationDelegateBuilder isolationDelegateBuilder;
+	private final StatisticsImplementor stats;
+	private final Dialect dialect;
+	private final int batchSize;
+
+	public JDBCContainerImpl(
+			LogicalConnection logicalConnection,
+	        TransactionIsolationDelegateBuilder isolationDelegateBuilder,
+			StatisticsImplementor stats,
+			Dialect dialect,
+			int batchSize) {
+		this.logicalConnection = logicalConnection;
+		this.isolationDelegateBuilder = isolationDelegateBuilder;
+		this.stats = stats;
+		this.dialect = dialect;
+		this.batchSize = batchSize;
+	}
+
+
+	public void doWork(Work work) throws HibernateException {
+		WorkspaceImpl workspace = new WorkspaceImpl();
+		workMap.put( work, workspace );
+		try {
+			work.performWork( workspace );
+		}
+		catch ( SQLException sqle ) {
+			doRelease( work );
+			throw convert( sqle, "Unable to perform requested work" );
+		}
+		finally {
+			if ( work.isConcise() ) {
+				release( work );
+			}
+		}
+	}
+
+	public void doWorkInSeperateTransaction(Work work) throws HibernateException {
+		if ( !work.isConcise() ) {
+			throw new HibernateException( "non-concise work cannot be done in seperate transaction" );
+		}
+		isolationDelegateBuilder.buildIsolationDelegate().doWorkInIsolation( work, this );
+	}
+
+	public void release(Work work) {
+		// needed for non-concise work to signal the fact that we are closed
+		// with the resources...
+		doRelease( work );
+		afterStatement();
+	}
+
+	private void doRelease(Work work) {
+		WorkspaceImpl workspace = ( WorkspaceImpl ) workMap.remove( work );
+		if ( workspace != null ) {
+			workspace.close();
+		}
+	}
+
+
+	// JDBCContainerImplementor impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public Dialect getDialect() {
+		return dialect;
+	}
+
+	public StatisticsImplementor getStatistics() {
+		return stats;
+	}
+
+	public SQLStatementLogger getStatementLogger() {
+		return logicalConnection.getStatementLogger();
+	}
+
+	public JDBCException convert(SQLException sqle, String message) {
+		return logicalConnection.convert( sqle, message );
+	}
+
+	public JDBCException convert(SQLException sqle, String message, String sql) {
+		return logicalConnection.convert( sqle, message, sql );
+	}
+
+	/**
+	 * Get the containers current logical connection.
+	 *
+	 * @return The current logical connection
+	 * @throws org.hibernate.HibernateException If the container is not logically connected.
+	 */
+	public LogicalConnection getLogicalConnection() throws HibernateException {
+		return logicalConnection;
+	}
+
+
+	/**
+	 * To be called after execution of each JDBC statement.  Used to
+	 * conditionally release the JDBC connection aggressively if
+	 * the configured release mode indicates.
+	 */
+	public void afterStatement() {
+		if ( getLogicalConnection().getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_STATEMENT ) {
+			// eventually needs to be...
+			//if ( !statementsToRelease.isEmpty() || container.getBatcher().isBatchInProgress() ) {
+			//
+			// the other option here is to simply make the PS associated with the batch register
+			// as a statementToRelease, that would cause the aggressive release to be skipped also
+//			if ( !statementsToRelease.isEmpty() ) {
+			if ( ! workMap.isEmpty() ) {
+				log.info( "Skipping aggresive-release due to open registered resources" );
+			}
+			else {
+				getLogicalConnection().aggressiveRelease();
+			}
+		}
+	}
+
+	public void cancelLastQuery() throws HibernateException {
+//		try {
+//			if (lastQuery!=null) {
+//				lastQuery.cancel();
+//			}
+//		}
+//		catch ( SQLException sqle) {
+//			throw JDBCExceptionHelper.convert( sqlExceptionConverter, sqle, "Could not cancel query" );
+//		}
+	}
+
+	public Connection borrowConnection() {
+		// TODO : implement, using new wrapper proxy code from JDBCContext
+		return null;
+	}
+
+	public Connection close() {
+		// TODO : ensure all resources get released
+//		Connection conn = logicalConnection.close();
+//		logicalConnection = null;
+//		return conn;
+		return null;
+	}
+
+
+	// Workspace impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public class WorkspaceImpl extends AbstractWorkspace implements Workspace {
+		public WorkspaceImpl() {
+			super( JDBCContainerImpl.this );
+		}
+
+		public Connection getConnection() {
+			return JDBCContainerImpl.this.getLogicalConnection().getConnection();
+		}
+
+		protected void opened() {
+			// TODO : implement "connection handle registration" logic
+		}
+
+		protected void closed() {
+			// TODO : release our "hold" on the connection
+		}
+	}
+}
\ No newline at end of file

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/JDBCContainerImplementor.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/JDBCContainerImplementor.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/impl/JDBCContainerImplementor.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,25 @@
+package org.hibernate.jdbc4.jdbc.impl;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.stat.StatisticsImplementor;
+import org.hibernate.JDBCException;
+import org.hibernate.jdbc4.jdbc.util.SQLStatementLogger;
+import org.hibernate.jdbc4.jdbc.JDBCContainer;
+import org.hibernate.jdbc4.jdbc.LogicalConnection;
+
+import java.sql.SQLException;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface JDBCContainerImplementor extends JDBCContainer {
+	public Dialect getDialect();
+	public SQLStatementLogger getStatementLogger();
+	public StatisticsImplementor getStatistics();
+
+	public LogicalConnection getLogicalConnection();
+
+	public JDBCException convert(SQLException sqle, String message);
+	public JDBCException convert(SQLException sqle, String message, String sql);
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/util/SQLStatementLogger.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/util/SQLStatementLogger.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/jdbc/util/SQLStatementLogger.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,40 @@
+package org.hibernate.jdbc4.jdbc.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Responsible for centralizing logging of all SQL statements.
+ *
+ * @author Steve Ebersole
+ */
+public class SQLStatementLogger {
+	private static final Log SQL_LOG = LogFactory.getLog( "org.hibernate.SQL" );
+
+	private boolean logToStdout;
+
+	/**
+	 * Construct a new SQLStatementLogger.
+	 *
+	 * @param logToStdout Should logged statements also get written to stdout?
+	 */
+	public SQLStatementLogger(boolean logToStdout) {
+		this.logToStdout = logToStdout;
+	}
+
+	public void setLogToStdout(boolean logToStdout) {
+		this.logToStdout = logToStdout;
+	}
+
+	/**
+	 * Log a SQL statement string.
+	 *
+	 * @param statement The SQL statement.
+	 */
+	public void logStatement(String statement) {
+		SQL_LOG.debug( statement );
+		if ( logToStdout ) {
+			System.out.println( "Hibernate: " + statement );
+		}
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/IsolationDelegate.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/IsolationDelegate.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/IsolationDelegate.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,11 @@
+package org.hibernate.jdbc4.tx;
+
+import org.hibernate.jdbc4.jdbc.Work;
+import org.hibernate.jdbc4.jdbc.impl.JDBCContainerImplementor;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface IsolationDelegate {
+	public void doWorkInIsolation(Work work, JDBCContainerImplementor jdbcContainer);
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/Listener.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/Listener.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/Listener.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,14 @@
+package org.hibernate.jdbc4.tx;
+
+import org.hibernate.HibernateException;
+
+/**
+ * todo: describe Listener
+ *
+ * @author Steve Ebersole
+ */
+public interface Listener {
+	public void afterBegin();
+	public void beforeCompletion() throws HibernateException;
+	public void afterCompletion(boolean successful);
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/TransactionCoordinator.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/TransactionCoordinator.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/TransactionCoordinator.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,120 @@
+package org.hibernate.jdbc4.tx;
+
+import org.hibernate.jdbc4.jdbc.LogicalConnection;
+import org.hibernate.jdbc4.Transaction;
+import org.hibernate.ConnectionReleaseMode;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Handles all transaction related tasks for a "group" of
+ * {@link org.hibernate.Session sessions}.  Responsible for coordinating all
+ * internal actions around the lifecycle of a conceptual transaction.
+ *
+ * @author Steve Ebersole
+ */
+public class TransactionCoordinator {
+
+	/**
+	 * A callback represents the way in which actual {@link org.hibernate.jdbc4.Transaction}
+	 * implementations notify the coordinator regarding events.
+	 */
+	public static interface Callback {
+		public void afterBegin();
+		public void beforeCompletion();
+		public void afterCompletion(boolean successful);
+		public void afterAfterCompletion();
+		public LogicalConnection getLogicalConnection();
+	}
+
+	private final TransactionFactory transactionFactory;
+	private final LogicalConnection logicalConnection;
+	private final List listeners = new ArrayList();
+
+	private Transaction currentHibernateTransaction;
+
+	public TransactionCoordinator(TransactionFactory transactionFactory, LogicalConnection logicalConnection) {
+		this.transactionFactory = transactionFactory;
+		this.logicalConnection = logicalConnection;
+	}
+
+	public void addListener(Listener listener) {
+		listeners.add( listener );
+	}
+
+	public void pulse() {
+		// attempt jta synch registration...
+	}
+
+	public LogicalConnection getLogicalConnection() {
+		return logicalConnection;
+	}
+
+	public Transaction getTransaction() {
+		if ( currentHibernateTransaction == null ) {
+			Callback callback;
+			if ( transactionFactory.areCallbacksLocalToHibernateTransactions() ) {
+				callback = new LocalCallback();
+			}
+			else {
+				callback = new NonLocalCallback();
+			}
+			currentHibernateTransaction = transactionFactory.createTransaction( callback );
+		}
+		return currentHibernateTransaction;
+	}
+
+	private class LocalCallback implements Callback {
+		public void afterBegin() {
+			Iterator itr = listeners.iterator();
+			while ( itr.hasNext() ) {
+				( ( Listener ) itr.next() ).afterBegin();
+			}
+		}
+
+		public void beforeCompletion() {
+			Iterator itr = listeners.iterator();
+			while ( itr.hasNext() ) {
+				( ( Listener ) itr.next() ).beforeCompletion();
+			}
+		}
+
+		public void afterCompletion(boolean successful) {
+			Iterator itr = listeners.iterator();
+			while ( itr.hasNext() ) {
+				( ( Listener ) itr.next() ).afterCompletion( successful );
+			}
+		}
+
+		public void afterAfterCompletion() {
+			if ( logicalConnection.getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_TRANSACTION ) {
+				logicalConnection.aggressiveRelease();
+			}
+		}
+
+		public LogicalConnection getLogicalConnection() {
+			return logicalConnection;
+		}
+	}
+
+	private class NonLocalCallback implements Callback {
+		// todo : implement this!
+		public void afterBegin() {
+		}
+
+		public void beforeCompletion() {
+		}
+
+		public void afterCompletion(boolean successful) {
+		}
+
+		public void afterAfterCompletion() {
+		}
+
+		public LogicalConnection getLogicalConnection() {
+			return logicalConnection;
+		}
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/TransactionFactory.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/TransactionFactory.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/TransactionFactory.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,81 @@
+package org.hibernate.jdbc4.tx;
+
+import java.util.Properties;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.HibernateException;
+import org.hibernate.jdbc4.Transaction;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Defines the contract for factories of {@link Transaction} instances.
+ * Concrete implementations are specified by the
+ * {@link org.hibernate.cfg.Environment#TRANSACTION_STRATEGY}
+ * (<i>hibernate.transaction.factory_class</i>) setting.
+ * <p/>
+ * Implementors must be threadsafe and should declare a public no-arg constructor.
+ *
+ * @see org.hibernate.Transaction
+ *
+ * @author Anton van Straaten
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public interface TransactionFactory {
+
+	/**
+	 * Configure from the given properties.
+	 *
+	 * @param props The defined properrties from which to pull our configuration
+	 * information.
+	 * @throws HibernateException Indicates issues configuring ourselves.
+	 */
+	public void configure(Properties props) throws HibernateException;
+
+	/**
+	 * The default {@link ConnectionReleaseMode} for JDBC connections.
+	 *
+	 * @return The default release mode to use in conjunction with this
+	 * transaction strategy if the user did not explicitly specify something else.
+	 */
+	public ConnectionReleaseMode getDefaultReleaseMode();
+
+	/**
+	 * Validate the state of this TransactionFactory in regards to the rest of the
+	 * Hibernate settings.
+	 * <p/>
+	 * This method is called once just after the {@link org.hibernate.SessionFactory}
+	 * has been built to give us a chance to validate our configured state against
+	 * the rest of the {@link org.hibernate.SessionFactory} settings.
+	 *
+	 * @param settings The {@link org.hibernate.SessionFactory} settings
+	 * @throws HibernateException Indicates a validation issue or setting mismatch.
+	 */
+	public void validate(Settings settings) throws HibernateException;
+
+	/**
+	 * Are transaction lifecycle callbacks originated from Hibernate
+	 * {@link Transaction transactions}?  The other general origination
+	 * is some external transaction-manager or transaction-monitor.
+	 *
+	 * @return True if transaction callbacks originate from local
+	 * Hibernate {@link Transaction transactions}; false otherwise.
+	 */
+	public boolean areCallbacksLocalToHibernateTransactions();
+
+	/**
+	 * Begin a transaction and return the associated <tt>Transaction</tt> instance.
+	 *
+	 * @param callback  The coordinator callback for this transaction.
+	 * @return The appropriate transaction instance.
+	 * @throws HibernateException Indicates a problem constructing a transaction.
+	 */
+	public Transaction createTransaction(TransactionCoordinator.Callback callback) throws HibernateException;
+
+	/**
+	 * Retrieve an isolation delegate appropritate for this transaction strategy.
+	 *
+	 * @return An isolation delegate.
+	 */
+	public IsolationDelegate createIsolationDelegate();
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/AbstractTransactionImpl.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/AbstractTransactionImpl.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/AbstractTransactionImpl.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,159 @@
+package org.hibernate.jdbc4.tx.impl;
+
+import org.hibernate.jdbc4.Transaction;
+import org.hibernate.jdbc4.tx.TransactionCoordinator;
+import org.hibernate.HibernateException;
+import org.hibernate.TransactionException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.transaction.Synchronization;
+import javax.transaction.Status;
+import java.util.List;
+
+/**
+ * todo: describe AbstractTransactionImpl
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractTransactionImpl implements Transaction {
+	public static final Log log = LogFactory.getLog( AbstractTransactionImpl.class );
+
+	protected final TransactionCoordinator.Callback callback;
+	private boolean begun;
+	private boolean rolledBack;
+	private boolean committed;
+	private boolean commitFailed;
+	private int timeout = -1;
+
+	protected AbstractTransactionImpl(TransactionCoordinator.Callback callback) {
+		this.callback = callback;
+	}
+
+	protected abstract void doBegin() throws TransactionException;
+	protected abstract void doCommit() throws TransactionException;
+	protected abstract void doRollback() throws TransactionException;
+
+	protected abstract List getLocalSynchronizations();
+
+	public boolean wasRolledBack() {
+		return rolledBack;
+	}
+
+	public boolean wasCommitted() {
+		return committed;
+	}
+
+	public boolean isActive() {
+		return begun && ! ( rolledBack || committed | commitFailed );
+	}
+
+	public final void begin() throws HibernateException {
+		if ( begun ) {
+			throw new TransactionException( "nested transactions not supported" );
+		}
+		if ( commitFailed ) {
+			throw new TransactionException( "cannot re-start transaction after failed commit" );
+		}
+
+		log.debug( "begin" );
+
+		doBegin();
+
+		begun = true;
+		committed = false;
+		rolledBack = false;
+
+		callback.afterBegin();
+	}
+
+	public final void commit() throws HibernateException {
+		if ( !begun ) {
+			throw new TransactionException( "Transaction not successfully started" );
+		}
+
+		log.debug( "committing" );
+
+		beforeTransactionCompletion();
+
+		try {
+			doCommit();
+			committed = true;
+			afterTransactionCompletion( Status.STATUS_COMMITTED );
+		}
+		catch ( Throwable t ) {
+			commitFailed = true;
+			afterTransactionCompletion( Status.STATUS_UNKNOWN );
+			throw new TransactionException( "commit failed", t );
+		}
+		finally {
+			callback.afterAfterCompletion();
+		}
+	}
+
+	public final void rollback() throws HibernateException {
+		if ( !begun && !commitFailed ) {
+			throw new TransactionException( "Transaction not successfully started" );
+		}
+
+		log.debug( "rolling back" );
+
+		if ( !commitFailed ) {
+			try {
+				doRollback();
+				rolledBack = true;
+				afterTransactionCompletion( Status.STATUS_ROLLEDBACK );
+			}
+			catch ( Throwable t ) {
+				afterTransactionCompletion( Status.STATUS_UNKNOWN );
+				throw new TransactionException( "rollback failed", t );
+			}
+			finally {
+				callback.afterAfterCompletion();
+			}
+		}
+	}
+
+	private void beforeTransactionCompletion() {
+		callback.beforeCompletion();
+
+		List synchronizations = getLocalSynchronizations();
+		if ( synchronizations != null ) {
+			for ( int i = 0; i < synchronizations.size(); i++ ) {
+				Synchronization sync = ( Synchronization ) synchronizations.get( i );
+				try {
+					sync.beforeCompletion();
+				}
+				catch (Throwable t) {
+					throw new TransactionException( "exception calling user Synchronization", t );
+				}
+			}
+		}
+	}
+
+	private void afterTransactionCompletion(int status) {
+		callback.afterCompletion( status == Status.STATUS_COMMITTED );
+
+		begun = false;
+		List synchronizations = getLocalSynchronizations();
+		if ( synchronizations != null ) {
+			for ( int i = 0; i < synchronizations.size(); i++ ) {
+				Synchronization sync = ( Synchronization ) synchronizations.get( i );
+				try {
+					sync.afterCompletion( status );
+				}
+				catch (Throwable t) {
+					throw new TransactionException( "exception calling user Synchronization", t );
+				}
+			}
+		}
+	}
+
+	public void setTimeout(int seconds) {
+		timeout = seconds;
+	}
+
+	public int getTimeout() {
+		return timeout;
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/IsolatedWorkspace.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/IsolatedWorkspace.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/IsolatedWorkspace.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,22 @@
+package org.hibernate.jdbc4.tx.impl;
+
+import org.hibernate.jdbc4.jdbc.impl.JDBCContainerImplementor;
+import org.hibernate.jdbc4.jdbc.impl.AbstractWorkspace;
+
+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/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCIsolationDelegate.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCIsolationDelegate.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCIsolationDelegate.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,84 @@
+package org.hibernate.jdbc4.tx.impl;
+
+import org.hibernate.jdbc4.tx.IsolationDelegate;
+import org.hibernate.jdbc4.jdbc.Work;
+import org.hibernate.jdbc4.jdbc.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;
+
+/**
+ * An isolation delegate which simply gets a different connection from the
+ * connection provider and uses that to achieve isolation.
+ * <p/>
+ * Warning, this strategy assumes that we are outside the scope of a JTA transaction
+ * if using a transacted data source...
+ *
+ * @author Steve Ebersole
+ */
+public class JDBCIsolationDelegate implements IsolationDelegate {
+
+	private static final Log log = LogFactory.getLog( JDBCIsolationDelegate.class );
+
+	public void doWorkInIsolation(Work work, JDBCContainerImplementor jdbcContainer) {
+		Connection connection = null;
+		boolean wasAutoCommit = false;
+		try {
+			connection = jdbcContainer.getLogicalConnection().getConnectionProvider().getConnection();
+			jdbcContainer.getStatistics().connect();
+			if ( connection.getAutoCommit() ) {
+				wasAutoCommit = true;
+				connection.setAutoCommit( false );
+			}
+
+			IsolatedWorkspace workspace = new IsolatedWorkspace( jdbcContainer, 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 jdbcContainer.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 {
+				jdbcContainer.getLogicalConnection().getConnectionProvider().closeConnection( connection );
+			}
+			catch ( Throwable ignore ) {
+				log.info( "unable to release connection obtained for isolated work : " + ignore );
+			}
+		}
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCTransaction.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCTransaction.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCTransaction.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,97 @@
+package org.hibernate.jdbc4.tx.impl;
+
+import org.hibernate.TransactionException;
+import org.hibernate.HibernateException;
+import org.hibernate.jdbc4.tx.TransactionCoordinator;
+
+import javax.transaction.Synchronization;
+import java.util.List;
+import java.util.ArrayList;
+import java.sql.SQLException;
+import java.sql.Connection;
+
+/**
+ * todo: describe JDBCTransaction
+ *
+ * @author Steve Ebersole
+ */
+public class JDBCTransaction extends AbstractTransactionImpl {
+
+	private Connection managedConnection;
+	private boolean wasInitiallyAutoCommit;
+	private List synchronizations;
+
+	public JDBCTransaction(TransactionCoordinator.Callback callback) {
+		super( callback );
+	}
+
+	protected void doBegin() throws TransactionException {
+		try {
+			if ( managedConnection != null ) {
+				throw new TransactionException( "Already have an associated managed connection" );
+			}
+			managedConnection = callback.getLogicalConnection().getConnection();
+			wasInitiallyAutoCommit = managedConnection.getAutoCommit();
+			if ( log.isDebugEnabled() ) {
+				log.debug( "initial autocommit status: " + wasInitiallyAutoCommit );
+			}
+			if ( wasInitiallyAutoCommit ) {
+				log.debug( "disabling autocommit" );
+				managedConnection.setAutoCommit( false );
+			}
+		}
+		catch( SQLException e ) {
+			throw new TransactionException( "JDBC begin transaction failed: ", e );
+		}
+	}
+
+	protected void doCommit() throws TransactionException {
+		try {
+			managedConnection.commit();
+			log.debug( "committed JDBC Connection" );
+		}
+		catch( SQLException e ) {
+			throw new TransactionException( "unable to commit against JDBC connection", e );
+		}
+		finally {
+			releaseManagedConnection();
+		}
+	}
+
+	protected void doRollback() throws TransactionException {
+		try {
+			managedConnection.rollback();
+			log.debug( "rolled JDBC Connection" );
+		}
+		catch( SQLException e ) {
+			throw new TransactionException( "unable to rollback against JDBC connection", e );
+		}
+		finally {
+			releaseManagedConnection();
+		}
+	}
+
+	private void releaseManagedConnection() {
+		try {
+			if ( wasInitiallyAutoCommit ) {
+				log.debug( "re-enabling autocommit" );
+				managedConnection.setAutoCommit( true );
+			}
+			managedConnection = null;
+		}
+		catch ( Exception sqle ) {
+			log.warn( "Could not toggle autocommit", sqle );
+		}
+	}
+
+	protected List getLocalSynchronizations() {
+		return synchronizations;
+	}
+
+	public void registerSynchronization(Synchronization synchronization) throws HibernateException {
+		if ( synchronizations == null ) {
+			synchronizations = new ArrayList();
+		}
+		synchronizations.add( synchronization );
+	}
+}

Added: trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCTransactionFactory.java
===================================================================
--- trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCTransactionFactory.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/main/java/org/hibernate/jdbc4/tx/impl/JDBCTransactionFactory.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,43 @@
+package org.hibernate.jdbc4.tx.impl;
+
+import org.hibernate.HibernateException;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.jdbc4.Transaction;
+import org.hibernate.jdbc4.tx.TransactionFactory;
+import org.hibernate.jdbc4.tx.TransactionCoordinator;
+import org.hibernate.jdbc4.tx.IsolationDelegate;
+import org.hibernate.cfg.Settings;
+
+import java.util.Properties;
+
+/**
+ * todo: describe JDBCTransactionFactory
+ *
+ * @author Steve Ebersole
+ */
+public class JDBCTransactionFactory implements TransactionFactory {
+	public void configure(Properties props) throws HibernateException {
+		//To change body of implemented methods use File | Settings | File Templates.
+	}
+
+	public ConnectionReleaseMode getDefaultReleaseMode() {
+		return ConnectionReleaseMode.AFTER_TRANSACTION;
+	}
+
+	public void validate(Settings settings) throws HibernateException {
+		//To change body of implemented methods use File | Settings | File Templates.
+	}
+
+	public boolean areCallbacksLocalToHibernateTransactions() {
+		return true;
+	}
+
+	public Transaction createTransaction(TransactionCoordinator.Callback callback) throws HibernateException {
+		return new JDBCTransaction( callback );
+	}
+
+	public IsolationDelegate createIsolationDelegate() {
+		return new JDBCIsolationDelegate();
+	}
+
+}

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/JournalingTransactionListener.java
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/JournalingTransactionListener.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/JournalingTransactionListener.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,31 @@
+package org.hibernate.jdbc4;
+
+import org.hibernate.jdbc4.tx.Listener;
+import org.hibernate.stat.StatisticsImplementor;
+
+/**
+ * todo: describe JournalingTransactionListener
+ *
+ * @author Steve Ebersole
+ */
+public class JournalingTransactionListener implements Listener {
+	private final StatisticsImplementor statistics;
+	public boolean afterBegin;
+	public boolean beforeCompletion;
+	public boolean afterCompletion;
+
+	public JournalingTransactionListener(StatisticsImplementor statistics) {
+		this.statistics = statistics;
+	}
+
+	public void afterBegin() {
+		afterBegin = true;
+	}
+	public void beforeCompletion() {
+		beforeCompletion = true;
+	}
+	public void afterCompletion(boolean successful) {
+		afterCompletion = true;
+		statistics.endTransaction( successful );
+	}
+}

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/LogicalConnectionObserver.java
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/LogicalConnectionObserver.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/LogicalConnectionObserver.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,29 @@
+package org.hibernate.jdbc4;
+
+import org.hibernate.jdbc4.jdbc.LogicalConnection;
+import org.hibernate.stat.StatisticsImplementor;
+
+/**
+ * todo: describe LogicalConnectionObserver
+ *
+ * @author Steve Ebersole
+ */
+public class LogicalConnectionObserver implements LogicalConnection.Observer {
+	private final StatisticsImplementor statisticsImplementor;
+
+	public int obtained = 0;
+	public int released = 0;
+
+	public LogicalConnectionObserver(StatisticsImplementor statisticsImplementor) {
+		this.statisticsImplementor = statisticsImplementor;
+	}
+
+	public void connectionObtained() {
+		obtained++;
+		statisticsImplementor.connect();
+	}
+
+	public void connectionReleased() {
+		released++;
+	}
+}

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/LineItem.hbm.xml
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/LineItem.hbm.xml	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/LineItem.hbm.xml	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.jdbc4.domain">
+
+    <class name="LineItem" table="ORDER_ITEM" lazy="true" >
+    	<id name="id" column="ITEM_ID" >
+    		<generator class="increment"/>
+    	</id>
+
+	    <many-to-one name="order" class="Order" column="ORDER_ID" cascade="none"/>
+	    <many-to-one name="product" class="Product" column="PRODUCT_ID" cascade="none"/>
+
+	    <property name="quantity" column="QTY" type="long"/>
+        <property name="discount" column="DSCNT" type="float"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/LineItem.java
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/LineItem.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/LineItem.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,68 @@
+package org.hibernate.jdbc4.domain;
+
+/**
+ * Implementation of LineItem.
+ *
+ * @author Steve Ebersole
+ */
+public class LineItem {
+	private Long id;
+	private Product product;
+	private Order order;
+	private int quantity;
+	private float discount;
+
+	public LineItem() {
+	}
+
+	public LineItem(Product product, int quantity) {
+		this.product = product;
+		this.quantity = quantity;
+	}
+
+	public LineItem(Product product, int quantity, float discount) {
+		this.product = product;
+		this.quantity = quantity;
+		this.discount = discount;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	private void setId(Long id) {
+		this.id = id;
+	}
+
+	public Product getProduct() {
+		return product;
+	}
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+
+	public Order getOrder() {
+		return order;
+	}
+
+	public void setOrder(Order order) {
+		this.order = order;
+	}
+
+	public int getQuantity() {
+		return quantity;
+	}
+
+	public void setQuantity(int quantity) {
+		this.quantity = quantity;
+	}
+
+	public float getDiscount() {
+		return discount;
+	}
+
+	public void setDiscount(float discount) {
+		this.discount = discount;
+	}
+}

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Order.hbm.xml
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Order.hbm.xml	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Order.hbm.xml	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.jdbc4.domain">
+
+    <class name="Order" table="T_ORDER" lazy="true" >
+    	<id name="id" column="ORDER_ID" type="long">
+    		<generator class="increment"/>
+    	</id>
+
+    	<property name="customer" column="CUST" type="string"/>
+	    <property name="salesperson" column="SALES" type="string"/>
+    	<property name="date" column="ORD_DT" type="java.util.Date"/>
+
+	    <set cascade="all-delete-orphan" inverse="true" name="lineItems">
+		    <key column="ORDER_ID"/>
+		    <one-to-many class="LineItem"/>
+	    </set>
+
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Order.java
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Order.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Order.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,89 @@
+package org.hibernate.jdbc4.domain;
+
+import java.util.Date;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * Implementation of Order.
+ *
+ * @author Steve Ebersole
+ */
+public class Order {
+	private Long id;
+	private String customer;
+	private String salesperson;
+	private Date date;
+	private Set lineItems = new HashSet();
+
+	public Order() {
+	}
+
+	public Order(String customer, String salesperson, Date date) {
+		this.customer = customer;
+		this.salesperson = salesperson;
+		this.date = date;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getCustomer() {
+		return customer;
+	}
+
+	public void setCustomer(String customer) {
+		this.customer = customer;
+	}
+
+	public String getSalesperson() {
+		return salesperson;
+	}
+
+	public void setSalesperson(String salesperson) {
+		this.salesperson = salesperson;
+	}
+
+	public Date getDate() {
+		return date;
+	}
+
+	public void setDate(Date date) {
+		this.date = date;
+	}
+
+	private Set getLineItems() {
+		return lineItems;
+	}
+
+	private void setLineItems(Set lineItems) {
+		this.lineItems = lineItems;
+	}
+
+	public Iterator getLineItemIterator() {
+		return getLineItems().iterator();
+	}
+
+	public LineItem addLineItem(Product product, int quantity) {
+		LineItem item = new LineItem( product, quantity );
+		addLineItem( item );
+		return item;
+	}
+
+	public LineItem addLineItem(Product product, int quantity, float discount) {
+		LineItem item = new LineItem( product, quantity, discount );
+		addLineItem( item );
+		return item;
+	}
+
+	private void addLineItem(LineItem item) {
+		item.setOrder( this );
+		lineItems.add( item );
+	}
+}

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Product.hbm.xml
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Product.hbm.xml	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Product.hbm.xml	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<hibernate-mapping package="org.hibernate.jdbc4.domain">
+
+    <class name="Product" table="PRODUCT" lazy="true">
+    	<id name="id" column="PROD_ID" >
+    		<generator class="increment"/>
+    	</id>
+
+    	<property name="description" type="string"/>
+	    <property name="sku" type="string"/>
+	    <property name="unitCost" column="UNIT_COST" type="double"/>
+	</class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Product.java
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Product.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/domain/Product.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,54 @@
+package org.hibernate.jdbc4.domain;
+
+/**
+ * Implementation of Product.
+ *
+ * @author Steve Ebersole
+ */
+public class Product {
+	private Long id;
+	private String sku;
+	private String description;
+	private Double unitCost;
+
+	public Product() {
+	}
+
+	public Product(String sku, String description, Double unitCost) {
+		this.sku = sku;
+		this.description = description;
+		this.unitCost = unitCost;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	private void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getSku() {
+		return sku;
+	}
+
+	public void setSku(String sku) {
+		this.sku = sku;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public Double getUnitCost() {
+		return unitCost;
+	}
+
+	public void setUnitCost(Double unitCost) {
+		this.unitCost = unitCost;
+	}
+}

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/AbstractTestCase.java
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/AbstractTestCase.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/AbstractTestCase.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,70 @@
+package org.hibernate.jdbc4.jdbc;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.test.tm.DummyTransactionManagerLookup;
+import org.hibernate.jdbc4.Settings;
+import org.hibernate.jdbc4.JournalingTransactionListener;
+import org.hibernate.jdbc4.LogicalConnectionObserver;
+import org.hibernate.jdbc4.jdbc.impl.JDBCContainerImpl;
+import org.hibernate.jdbc4.tx.TransactionCoordinator;
+import org.hibernate.jdbc4.tx.IsolationDelegate;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+
+/**
+ * todo: describe AbstractTestCase
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractTestCase extends TestCase {
+
+	protected Settings settings = new Settings();
+	protected JournalingTransactionListener transactionListener = new JournalingTransactionListener( settings.getStatistics() );
+	protected LogicalConnectionObserver connectionObserver = new LogicalConnectionObserver( settings.getStatistics() );
+	protected LogicalConnectionBuilder logicalConnectionBuilder = new LogicalConnectionBuilder( settings, connectionObserver );
+
+	protected TransactionCoordinator coordinator;
+	protected JDBCContainerImpl jdbcContainer;
+
+	public AbstractTestCase(String name) {
+		super( name );
+	}
+
+	protected void setUp() throws Exception {
+		super.setUp();
+		LogicalConnection lc = logicalConnectionBuilder.buiLogicalConnection( null );
+		coordinator = new TransactionCoordinator( settings.getTransactionFactory(), lc );
+		coordinator.addListener( transactionListener );
+
+		IsolationDelegateBuilder isolationDelegateBuilder = new IsolationDelegateBuilder();
+		jdbcContainer = new JDBCContainerImpl( lc, isolationDelegateBuilder, settings.getStatistics(), settings.getDialect(), -1 );
+	}
+
+	protected void tearDown() throws Exception {
+		coordinator.getLogicalConnection().close();
+		coordinator = null;
+
+		jdbcContainer.close();
+		super.tearDown();
+	}
+
+	protected String getBaseForMappings() {
+		return "org/hibernate/jdbc4/domain";
+	}
+
+	protected String[] getMappings() {
+		return new String[] { "/Order.hbm.xml", "/LineItem.hbm.xml", "/Product.hbm.xml" };
+	}
+
+	protected void configure(Configuration cfg) {
+		cfg.setProperty( Environment.RELEASE_CONNECTIONS, settings.getConnectionReleaseMode().toString() );
+		cfg.setProperty( Environment.CONNECTION_PROVIDER, settings.getConnectionProvider().getClass().getName() );
+		cfg.setProperty( Environment.TRANSACTION_MANAGER_STRATEGY, DummyTransactionManagerLookup.class.getName() );
+	}
+
+	protected class IsolationDelegateBuilder implements JDBCContainerImpl.TransactionIsolationDelegateBuilder {
+		public IsolationDelegate buildIsolationDelegate() {
+			return settings.getTransactionFactory().createIsolationDelegate();
+		}
+	}
+}

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/command/BasicCommandTest.java
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/command/BasicCommandTest.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/command/BasicCommandTest.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,104 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.jdbc4.jdbc.AbstractTestCase;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.Connection;
+import java.sql.ResultSet;
+
+/**
+ * todo: describe BasicCommandTest
+ *
+ * @author Steve Ebersole
+ */
+public class BasicCommandTest extends AbstractTestCase {
+	private static final String INSERT = "insert into T_ORDER ( ORDER_ID, CUST, SALES, ORD_DT ) VALUES ( ?, ?, ?, ? )";
+	private static final String DELETE = "delete from T_ORDER where ORDER_ID = ?";
+
+	public BasicCommandTest(String name) {
+		super( name );
+	}
+
+	public void testBasicQueryCommandInterface() {
+		String sql = "select count(*) from T_ORDER";
+		CountExtracter extracter = new CountExtracter();
+
+		QueryCommandImpl command = new QueryCommandImpl( sql );
+		command.execute( jdbcContainer, extracter );
+	}
+
+	public void testBasicExecutionCommandInterface() {
+		new ExecutionCommandImpl( INSERT ).execute(
+				jdbcContainer,
+		        new ParameterBinds() {
+					public void bindParameterValues(PreparedStatement stmnt) throws SQLException {
+						Hibernate.LONG.nullSafeSet( stmnt, new Long( 1 ), 1 );
+						Hibernate.STRING.nullSafeSet( stmnt, "Steve", 2 );
+						Hibernate.STRING.nullSafeSet( stmnt, "Ben", 3 );
+						Hibernate.TIMESTAMP.nullSafeSet( stmnt, new java.util.Date(), 4 );
+					}
+				}
+		);
+
+		new ExecutionCommandImpl( DELETE ).execute(
+				jdbcContainer,
+				new ParameterBinds() {
+					public void bindParameterValues(PreparedStatement stmnt) throws SQLException {
+						Hibernate.LONG.nullSafeSet( stmnt, new Long( 1 ), 1 );
+					}
+				}
+		);
+	}
+
+	public void testBasicExecutionCommand2Interface() {
+		new ExecutionCommand2Impl( INSERT ) {
+			protected void bindParameterValues(PreparedStatement statement) throws SQLException {
+				Hibernate.LONG.nullSafeSet( statement, new Long( 1 ), 1 );
+				Hibernate.STRING.nullSafeSet( statement, "Steve", 2 );
+				Hibernate.STRING.nullSafeSet( statement, "Ben", 3 );
+				Hibernate.TIMESTAMP.nullSafeSet( statement, new java.util.Date(), 4 );
+			}
+		}.execute( jdbcContainer );
+
+		new ExecutionCommand2Impl( DELETE ) {
+			protected void bindParameterValues(PreparedStatement statement) throws SQLException {
+				Hibernate.LONG.nullSafeSet( statement, new Long( 1 ), 1 );
+			}
+		}.execute( jdbcContainer );
+	}
+
+	private static class BasicCreator implements StatementCreator {
+		public PreparedStatement createPreparedStatement(Connection connection, String sql) throws SQLException {
+			return connection.prepareStatement( sql );
+		}
+
+		public boolean isStatementCallable() {
+			return false;
+		}
+	}
+
+	private static class BasicResultExtracter implements ResultSetProcessor {
+
+		public void processResults(ResultSet results) throws SQLException, HibernateException {
+			while ( results.next() ) {
+				processRow( results );
+			}
+		}
+
+		private void processRow(ResultSet results) throws SQLException, HibernateException {
+			results.getObject( 1 );
+		}
+	}
+
+	private static class CountExtracter implements ResultSetProcessor {
+		private long result;
+		public void processResults(ResultSet results) throws SQLException, HibernateException {
+			results.next();
+			result = results.getLong( 1 );
+		}
+	}
+
+}

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/command/BasicPersisterUsageTest.java
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/command/BasicPersisterUsageTest.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/command/BasicPersisterUsageTest.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,324 @@
+package org.hibernate.jdbc4.jdbc.command;
+
+import org.hibernate.jdbc4.jdbc.AbstractTestCase;
+import org.hibernate.jdbc4.domain.Order;
+import org.hibernate.jdbc.Expectation;
+import org.hibernate.jdbc.Expectations;
+import org.hibernate.type.Type;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.Hibernate;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.hql.ast.exec.StatementExecutor;
+import org.hibernate.exception.JDBCExceptionHelper;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.util.ArrayHelper;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.Versioning;
+
+import java.util.Date;
+import java.util.Arrays;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.io.Serializable;
+
+/**
+ * Used to illustrate what use of this new JDBC API might look like
+ * when utilized from the persisters to perform the various DML
+ * operations against an entity.
+ * <p/>
+ * This is a somewhat simplified view in that we do not account for
+ * multi-table mappings of any sort.
+ *
+ * @author Steve Ebersole
+ */
+public class BasicPersisterUsageTest extends AbstractTestCase {
+	private static final String INSERT = "insert into T_ORDER ( CUST, SALES, ORD_DT, ORDER_ID ) VALUES ( ?, ?, ?, ? )";
+	private static final String UPDATE = "update T_ORDER set CUST = ?, SALES = ?, ORD_DT = ? where ORDER_ID = ?";
+	private static final String DELETE = "delete from T_ORDER where ORDER_ID = ?";
+
+	// represent things that would be known to the persister (the sql above falls into this also)
+	private static final Type ID_TYPE = Hibernate.LONG;
+	private static final Type[] TYPES = new Type[] { Hibernate.STRING, Hibernate.STRING, Hibernate.TIMESTAMP };
+
+	public BasicPersisterUsageTest(String name) {
+		super( name );
+	}
+
+	public void testInsertUpdateDelete() {
+		Long id = new Long( 1 );
+
+		// instantiate and populate the entity to be used in DML operations
+		Order order = new Order();
+		order.setId( id );
+		order.setCustomer( "steve" );
+		order.setDate( new Date() );
+		order.setSalesperson( "tom" );
+
+		// first we need to perform the insert.  In effort to mimic this behavior
+		// as close as possible, I go through most of the processing of the system
+		// starting from an entity to be saved to try and get the best illustration...
+
+		// first, extract the entity state (this corresponds to the fields paramater discussed above).
+		Object[] tupleState = sfi().getEntityPersister( Order.class.getName() ).getPropertyValues( order, EntityMode.POJO );
+
+		// next determine which fields are insertable (corresponds to the notNull parameter discussion).
+		// <p/>
+		// Here I simply build an all-true-array since that functionality is not exposed on persister...
+		boolean[] notNull = new boolean[ tupleState.length ];
+		Arrays.fill( notNull, true );
+
+		insert( id, tupleState, notNull, 0, INSERT, order );
+
+
+		// now, lets perform an update...
+		order.setSalesperson( "ben" );
+		Object[] newTupleState = sfi().getEntityPersister( Order.class.getName() ).getPropertyValues( order, EntityMode.POJO );
+		int[] dirtyFields = new int[] { 1 }; // salesperson is the second (index=1) mapped property.
+
+	}
+
+	/**
+	 * Mimic the insert method on persister.
+	 * <p/>
+	 * Note that the persister version does take one additional parameter
+	 * which I have dropped here: the session...
+	 *
+	 * @param id this is the Hibernate generated id value for this entity; whether or not that
+	 * vale gets used for the insertion depends on the id-gen-strategy
+	 * @param fields this is the entity state to be used in the insertions (explicitly not the current state)
+	 * @param notNull a boolean array which is parallel with the fields array and specifies which
+	 * field values should get bound; should really be called insertable are something similiar
+	 * @param j this is the table number into which we are inserting; used for multi-table mappings, ignored here
+	 * @param sql the SQL INSERT string
+	 * @param object the entity instance
+	 */
+	private void insert(
+			final Serializable id,
+			final Object[] fields,
+			final boolean[] notNull,
+			final int j,
+			final String sql,
+			final Object object) {
+		// this is an inst var on persister:
+		final boolean[][] propertyColumnInsertable = new boolean[3][1];
+		propertyColumnInsertable[0][0] = true;
+		propertyColumnInsertable[1][0] = true;
+		propertyColumnInsertable[2][0] = true;
+
+		// the actual StatementCreator to use would need to be calculated; here I just use an
+		// appropriate value
+		final Expectation expectation = Expectations.appropriateExpectation( ExecuteUpdateResultCheckStyle.COUNT );
+		StatementCreator insertStatementCreator = new InsertCommand.BasicCreator();
+		InsertCommand insert = new InsertCommand( INSERT, insertStatementCreator );
+
+		ParameterBinds binds = new ParameterBinds() {
+			public void bindParameterValues(PreparedStatement stmnt) throws SQLException, HibernateException {
+				int index = 1;
+				index += expectation.prepare( stmnt );
+
+				// Write the values of fields onto the prepared statement - we MUST use the state at the time the
+				// insert was issued (cos of foreign key constraints). Not necessarily the object's current state
+
+				dehydrate( id, fields, null, notNull, propertyColumnInsertable, j, stmnt, null, index );
+			}
+		};
+
+		// again, the executor would need to be calculated...
+		Executor executor = new InsertCommand.BasicExecutor();
+		insert.execute( jdbcContainer, binds, executor );
+	}
+
+//	protected boolean update(
+//			final Serializable id,
+//	        final Object[] fields,
+//	        final Object[] oldFields,
+//	        final Object rowId,
+//	        final boolean[] includeProperty,
+//	        final int j,
+//	        final Object oldVersion,
+//	        final Object object,
+//	        final String sql,
+//	        final SessionImplementor session) throws HibernateException {
+//
+//		final boolean useVersion = j == 0 && isVersioned();
+//		final Expectation expectation = Expectations.appropriateExpectation( updateResultCheckStyles[j] );
+//		final boolean callable = isUpdateCallable( j );
+//		final boolean useBatch = j == 0 && expectation.canBeBatched() && isBatchable(); //note: updates to joined tables can't be batched...
+//
+//		if ( log.isTraceEnabled() ) {
+//			log.trace( "Updating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
+//			if ( useVersion ) {
+//				log.trace( "Existing version: " + oldVersion + " -> New version: " + fields[getVersionProperty()] );
+//			}
+//		}
+//
+//		try {
+//
+//			int index = 1; // starting index
+//			final PreparedStatement update;
+//			if ( useBatch ) {
+//				if ( callable ) {
+//					update = session.getBatcher().prepareBatchCallableStatement( sql );
+//				}
+//				else {
+//					update = session.getBatcher().prepareBatchStatement( sql );
+//				}
+//			}
+//			else {
+//				if ( callable ) {
+//					update = session.getBatcher().prepareCallableStatement( sql );
+//				}
+//				else {
+//					update = session.getBatcher().prepareStatement( sql );
+//				}
+//			}
+//
+//			try {
+//
+//				index+= expectation.prepare( update );
+//
+//				//Now write the values of fields onto the prepared statement
+//				index = dehydrate( id, fields, rowId, includeProperty, propertyColumnUpdateable, j, update, session, index );
+//
+//				// Write any appropriate versioning conditional parameters
+//				if ( useVersion && Versioning.OPTIMISTIC_LOCK_VERSION == entityMetamodel.getOptimisticLockMode() ) {
+//					if ( checkVersion( includeProperty ) ) {
+//						getVersionType().nullSafeSet( update, oldVersion, index, session );
+//					}
+//				}
+//				else if ( entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION && oldFields != null ) {
+//					boolean[] versionability = getPropertyVersionability(); //TODO: is this really necessary????
+//					boolean[] includeOldField = entityMetamodel.getOptimisticLockMode() == Versioning.OPTIMISTIC_LOCK_ALL ?
+//							getPropertyUpdateability() : includeProperty;
+//					Type[] types = getPropertyTypes();
+//					for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
+//						boolean include = includeOldField[i] &&
+//								isPropertyOfTable( i, j ) &&
+//								versionability[i]; //TODO: is this really necessary????
+//						if ( include ) {
+//							boolean[] settable = types[i].toColumnNullness( oldFields[i], getFactory() );
+//							types[i].nullSafeSet(
+//									update,
+//									oldFields[i],
+//									index,
+//									settable,
+//									session
+//								);
+//							index += ArrayHelper.countTrue(settable);
+//						}
+//					}
+//				}
+//
+//				if ( useBatch ) {
+//					session.getBatcher().addToBatch( expectation );
+//					return true;
+//				}
+//				else {
+//					return check( update.executeUpdate(), id, j, expectation, update );
+//				}
+//
+//			}
+//			catch ( SQLException sqle ) {
+//				if ( useBatch ) {
+//					session.getBatcher().abortBatch( sqle );
+//				}
+//				throw sqle;
+//			}
+//			finally {
+//				if ( !useBatch ) {
+//					session.getBatcher().closeStatement( update );
+//				}
+//			}
+//
+//		}
+//		catch ( SQLException sqle ) {
+//			throw JDBCExceptionHelper.convert(
+//					getFactory().getSQLExceptionConverter(),
+//					sqle,
+//					"could not update: " + MessageHelper.infoString( this, id, getFactory() ),
+//					sql
+//				);
+//		}
+//	}
+
+	/**
+	 * Again, mimic some persister functionality.  This is the persister method
+	 * which drives parameter binding.  The thought is that the first round of integrating
+	 * this stuff into usage I could just have the various ParameterBinds relating to
+	 * these persister operations "call out" to this method...
+	 * <p/>
+	 * Again, I have removed some parameters which are irrelevant for these illustrations...
+	 *
+	 * @param id The entity's id value.
+	 * @param fields The fields to bind
+	 * @param includeProperty Which properties are to be bound
+	 * @param includeColumns To which columns mapped by the properties should we bind
+	 * @param j table number ...
+	 * @param ps The statement to which to bind the proper bind vars
+	 * @param index The position from which to start binding...
+	 * @return the position at which we left off binding...
+	 */
+	protected int dehydrate(
+			final Serializable id,
+	        final Object[] fields,
+	        final Object rowId,
+	        final boolean[] includeProperty,
+	        final boolean[][] includeColumns,
+	        final int j,
+	        final PreparedStatement ps,
+	        final SessionImplementor session,
+	        int index) throws SQLException {
+
+//		if ( log.isTraceEnabled() ) {
+//			log.trace( "Dehydrating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
+//		}
+
+//		int propertySpan = entityMetamodel.getPropertySpan();
+		int propertySpan = 3;
+		for ( int i = 0; i < propertySpan; i++ ) {
+			if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
+				getPropertyTypes()[i].nullSafeSet( ps, fields[i], index, includeColumns[i], session );
+				//index += getPropertyColumnSpan( i );
+				index += ArrayHelper.countTrue( includeColumns[i] ); //TODO:  this is kinda slow...
+			}
+		}
+
+		if ( rowId != null ) {
+			ps.setObject( index, rowId );
+			index += 1;
+		}
+		else if ( id != null ) {
+			getIdentifierType().nullSafeSet( ps, id, index, session );
+			index += getIdentifierColumnSpan();
+		}
+
+		return index;
+
+	}
+
+	private int getIdentifierColumnSpan() {
+		return 1;
+	}
+
+	private Type getIdentifierType() {
+		return ID_TYPE;
+	}
+
+	private Type[] getPropertyTypes() {
+		return TYPES;
+	}
+
+	private boolean isPropertyOfTable(int propertyIndex, int tableIndex) {
+		// we only have one table...
+		return true;
+	}
+
+	private static class InsertCommand extends ExecutionCommandImpl {
+		public InsertCommand(String sql, StatementCreator creator) {
+			super( sql, creator );
+		}
+	}
+
+}

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/impl/BasicWorkTest.java
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/impl/BasicWorkTest.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/jdbc/impl/BasicWorkTest.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,86 @@
+package org.hibernate.jdbc4.jdbc.impl;
+
+import org.hibernate.jdbc4.jdbc.AbstractTestCase;
+import org.hibernate.jdbc4.jdbc.Workspace;
+import org.hibernate.jdbc4.jdbc.Work;
+import org.hibernate.jdbc4.Transaction;
+import org.hibernate.HibernateException;
+
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+
+/**
+ * todo: describe BasicWorkTest
+ *
+ * @author Steve Ebersole
+ */
+public class BasicWorkTest extends AbstractTestCase {
+	public BasicWorkTest(String name) {
+		super( name );
+	}
+
+	public void testBasicWorkInterface() throws Throwable {
+		Transaction txn = coordinator.getTransaction();
+		txn.begin();
+
+		Work work = new Work() {
+			private String sql = "select * from T_ORDER";
+			public void performWork(Workspace workspace) throws HibernateException {
+				try {
+					PreparedStatement stmnt = workspace.getConnection().prepareStatement( sql );
+					workspace.register( stmnt );
+					ResultSet results = stmnt.executeQuery();
+					workspace.register( results );
+					while ( results.next() ) {
+						results.getObject( 1 );
+					}
+				}
+				catch( SQLException sqle ) {
+					throw workspace.convert( sqle, "could not perform query", sql );
+				}
+			}
+
+			public boolean isConcise() {
+				return true;
+			}
+		};
+		jdbcContainer.doWork( work );
+
+		txn.commit();
+
+		assertEquals( 1, settings.getStatistics().getConnectCount() );
+	}
+
+	public void testIsolatedWork() throws Throwable {
+		Transaction txn = coordinator.getTransaction();
+		txn.begin();
+
+		Work workToIsolate = new Work() {
+			private String sql = "select * from T_ORDER";
+			public void performWork(Workspace workspace) throws HibernateException {
+				try {
+					PreparedStatement stmnt = workspace.getConnection().prepareStatement( sql );
+					workspace.register( stmnt );
+					ResultSet results = stmnt.executeQuery();
+					workspace.register( results );
+					while ( results.next() ) {
+						results.getObject( 1 );
+					}
+				}
+				catch( SQLException sqle ) {
+					throw workspace.convert( sqle, "could not perform query", sql );
+				}
+			}
+
+			public boolean isConcise() {
+				return true;
+			}
+		};
+		jdbcContainer.doWorkInSeperateTransaction( workToIsolate );
+
+		txn.commit();
+
+		assertEquals( 2, settings.getStatistics().getConnectCount() );
+	}
+}

Added: trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/tx/BasicTransactionCoordinatorTest.java
===================================================================
--- trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/tx/BasicTransactionCoordinatorTest.java	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/java/org/hibernate/jdbc4/tx/BasicTransactionCoordinatorTest.java	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,49 @@
+package org.hibernate.jdbc4.tx;
+
+import junit.framework.TestCase;
+import org.hibernate.jdbc4.jdbc.LogicalConnection;
+import org.hibernate.jdbc4.jdbc.LogicalConnectionBuilder;
+import org.hibernate.jdbc4.Transaction;
+import org.hibernate.jdbc4.Settings;
+import org.hibernate.jdbc4.LogicalConnectionObserver;
+import org.hibernate.jdbc4.JournalingTransactionListener;
+
+/**
+ * todo: describe BasicTransactionCoordinatorTest
+ *
+ * @author Steve Ebersole
+ */
+public class BasicTransactionCoordinatorTest extends TestCase {
+
+	private Settings settings = new Settings();
+	private JournalingTransactionListener transactionListener = new JournalingTransactionListener( settings.getStatistics() );
+	private LogicalConnectionObserver connectionObserver = new LogicalConnectionObserver( settings.getStatistics() );
+	private LogicalConnectionBuilder logicalConnectionBuilder = new LogicalConnectionBuilder( settings, connectionObserver );
+	private TransactionCoordinator coordinator;
+
+	protected void setUp() throws Exception {
+		LogicalConnection lc = logicalConnectionBuilder.buiLogicalConnection( null );
+		coordinator = new TransactionCoordinator( settings.getTransactionFactory(), lc );
+		coordinator.addListener( transactionListener );
+	}
+
+	protected void tearDown() throws Exception {
+		coordinator.getLogicalConnection().close();
+		coordinator = null;
+	}
+
+	public void testBasicTransactionCoordinatorUsage() {
+		Transaction txn = coordinator.getTransaction();
+		txn.begin();
+		txn.commit();
+
+		assertTrue( transactionListener.afterBegin );
+		assertTrue( transactionListener.beforeCompletion );
+		assertTrue( transactionListener.afterCompletion );
+
+		// connection obtained because of starting the txn
+		assertEquals( 1, connectionObserver.obtained );
+		assertEquals( 1, connectionObserver.released );
+	}
+
+}

Added: trunk/sandbox/jdbc/src/test/resources/hibernate.properties
===================================================================
--- trunk/sandbox/jdbc/src/test/resources/hibernate.properties	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/resources/hibernate.properties	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,95 @@
+hibernate.query.substitutions yes 'Y', no 'N'
+
+hibernate.show_sql true
+hibernate.format_sql true
+
+#hibernate.jdbc.use_streams_for_binary true
+#hibernate.jdbc.use_get_generated_keys true
+
+hibernate.connection.pool_size 1
+hibernate.max_fetch_depth 1
+
+hibernate.cglib.use_reflection_optimizer false
+hibernate.bytecode.use_reflection_optimizer false
+hibernate.bytecode.provider javassist
+
+hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider
+##hibernate.connection.isolation 1
+
+## DB Template
+#hibernate.dialect
+#hibernate.connection.username
+#hibernate.connection.password
+#hibernate.connection.driver_class
+#hibernate.connection.url
+
+## HypersonicSQL
+hibernate.dialect org.hibernate.dialect.HSQLDialect
+hibernate.connection.driver_class org.hsqldb.jdbcDriver
+hibernate.connection.username sa
+hibernate.connection.password
+hibernate.connection.url jdbc:hsqldb:.
+#hibernate.use_sql_comments true
+##hibernate.connection.shutdown true
+
+## MS SQL Server (local - sqljdbc)
+#hibernate.dialect org.hibernate.dialect.SQLServerDialect
+#hibernate.connection.url jdbc:sqlserver://localhost:1681
+#hibernate.connection.driver_class com.microsoft.sqlserver.jdbc.SQLServerDriver
+#hibernate.connection.isolation 4096
+#hibernate.connection.username sa
+#hibernate.connection.password @dmin
+##hibernate.connection.username hibernate
+##hibernate.connection.password hibernate
+
+## Oracle 8i (on thor)
+#hibernate.dialect org.hibernate.dialect.OracleDialect
+#hibernate.connection.username scott
+#hibernate.connection.password tiger
+#hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver
+#hibernate.connection.url jdbc:oracle:thin:@192.168.1.104:1521:soma
+
+## Oracle 10g (local)
+#hibernate.dialect org.hibernate.dialect.Oracle9Dialect
+#hibernate.connection.username hibernate
+#hibernate.connection.password hibernate
+#hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver
+#hibernate.connection.url jdbc:oracle:thin:@steve-jboss:1521:ora10g
+#hibernate.use_sql_comments true
+
+## Oracle 8i (emulate 8i using my local 10g)
+#hibernate.dialect org.hibernate.dialect.OracleDialect
+#hibernate.connection.username hibernate
+#hibernate.connection.password hibernate
+#hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver
+#hibernate.connection.url jdbc:oracle:thin:@steve-jboss:1521:ora10g
+
+## Derby
+#hibernate.dialect org.hibernate.dialect.DerbyDialect
+#hibernate.connection.driver_class org.apache.derby.jdbc.EmbeddedDriver
+#hibernate.connection.url jdbc:derby:build/derby/hibernate;create=true
+
+## MySQL
+#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
+#hibernate.connection.driver_class com.mysql.jdbc.Driver
+#hibernate.connection.url jdbc:mysql:///test
+#hibernate.connection.username hibernate
+#hibernate.connection.password hibernate
+#hibernate.use_sql_comments true
+
+
+###################  JBoss QA Lab Databases ###########################
+
+## Sybase (jConnect)
+#hibernate.dialect org.hibernate.dialect.SybaseDialect
+#hibernate.connection.driver_class com.sybase.jdbc2.jdbc.SybDriver
+#hibernate.connection.username sa
+#hibernate.connection.password sasasa
+#hibernate.connection.url jdbc:sybase:Tds:co3061835-a:5000/tempdb
+
+## Oracle 10g
+#hibernate.dialect org.hibernate.dialect.Oracle9Dialect
+#hibernate.connection.username
+#hibernate.connection.password
+#hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver
+#hibernate.connection.url jdbc:oracle:thin:@dev01-priv:1521:qadb01
\ No newline at end of file

Added: trunk/sandbox/jdbc/src/test/resources/log4j.properties
===================================================================
--- trunk/sandbox/jdbc/src/test/resources/log4j.properties	2006-08-21 17:05:00 UTC (rev 10303)
+++ trunk/sandbox/jdbc/src/test/resources/log4j.properties	2006-08-21 17:21:49 UTC (rev 10304)
@@ -0,0 +1,51 @@
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
+
+
+
+#### set log levels - for more verbose logging change 'info' to 'debug' ###
+
+log4j.rootLogger=warn, stdout
+
+#log4j.logger.org.hibernate=debug
+log4j.logger.org.hibernate=info
+#log4j.logger.org.hibernate=warn
+
+
+log4j.logger.org.hibernate.jdbc4=debug
+
+#log4j.logger.org.hibernate.cache debug
+#log4j.logger.org.jboss.cache debug
+
+#log4j.logger.org.hibernate.engine.query=debug
+#log4j.logger.org.hibernate.engine.StatefulPersistenceContext=debug
+#log4j.logger.org.hibernate.engine.ActionQueue=debug
+
+### log HQL query parser activity
+log4j.logger.org.hibernate.hql.ast=debug
+#log4j.logger.org.hibernate.hql.ast.AST=debug
+
+### log just the SQL
+#log4j.logger.org.hibernate.SQL=debug
+
+### log JDBC bind parameters ###
+#log4j.logger.org.hibernate.type=info
+log4j.logger.org.hibernate.type=debug
+
+### log schema export/update ###
+log4j.logger.org.hibernate.tool.hbm2ddl=debug
+
+### log cache activity ###
+#log4j.logger.org.hibernate.cache=debug
+
+### log transaction activity
+#log4j.logger.org.hibernate.transaction=debug
+
+### log JDBC resource acquisition
+#log4j.logger.org.hibernate.jdbc=debug
+
+### enable the following line if you want to track down connection ###
+### leakages when using DriverManagerConnectionProvider ###
+#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace




More information about the hibernate-commits mailing list