diff --git a/hibernate-core/src/main/java/org/hibernate/Session.java b/hibernate-core/src/main/java/org/hibernate/Session.java
index 0a16a70e48..e3b30415b6 100644
--- a/hibernate-core/src/main/java/org/hibernate/Session.java
+++ b/hibernate-core/src/main/java/org/hibernate/Session.java
@@ -25,6 +25,8 @@
package org.hibernate;
import java.io.Serializable;
import java.sql.Connection;
+
+import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.stat.SessionStatistics;
@@ -917,6 +919,17 @@ public interface Session extends Serializable {
*/
public void doWork(Work work) throws HibernateException;
+ /**
+ * Controller for allowing users to perform JDBC related work using the Connection
+ * managed by this Session, returning the result from calling work.execute()
+ * ({@link ReturningWork.execute(Connection)}/
+ *
+ * @param work The work to be performed.
+ * @return the result from calling work.execute()
.
+ * @throws HibernateException Generally indicates wrapped {@link java.sql.SQLException}
+ */
+ public T doReturningWork(ReturningWork work) throws HibernateException;
+
/**
* Disconnect the session from its underlying JDBC connection. This is intended for use in cases where the
* application has supplied the JDBC connection to the session and which require long-sessions (aka, conversations).
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java
index 39bf9ae961..cc5125ac17 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java
@@ -42,8 +42,9 @@ import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl;
import org.hibernate.engine.transaction.spi.TransactionContext;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
-import org.hibernate.jdbc.ReturningWork;
-import org.hibernate.jdbc.Work;
+import org.hibernate.jdbc.WorkExecutorVisitable;
+import org.hibernate.jdbc.WorkExecutor;
+
import org.jboss.logging.Logger;
/**
@@ -184,32 +185,11 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
}
}
- public void coordinateWork(Work work) {
- Connection connection = getLogicalConnection().getDistinctConnectionProxy();
- try {
- work.execute( connection );
- getLogicalConnection().afterStatementExecution();
- }
- catch ( SQLException e ) {
- throw sqlExceptionHelper().convert( e, "error executing work" );
- }
- finally {
- try {
- if ( ! connection.isClosed() ) {
- connection.close();
- }
- }
- catch (SQLException e) {
- LOG.debug("Error closing connection proxy", e);
- }
- }
- }
-
@Override
- public T coordinateWork(ReturningWork work) {
+ public T coordinateWork(WorkExecutorVisitable work) {
Connection connection = getLogicalConnection().getDistinctConnectionProxy();
try {
- T result = work.execute( connection );
+ T result = work.accept( new WorkExecutor(), connection );
getLogicalConnection().afterStatementExecution();
return result;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/JdbcCoordinator.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/JdbcCoordinator.java
index b693081470..6c7b966562 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/JdbcCoordinator.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/JdbcCoordinator.java
@@ -26,9 +26,7 @@ package org.hibernate.engine.jdbc.spi;
import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
-import org.hibernate.id.IntegralDataTypeHolder;
-import org.hibernate.jdbc.ReturningWork;
-import org.hibernate.jdbc.Work;
+import org.hibernate.jdbc.WorkExecutorVisitable;
import java.io.Serializable;
import java.sql.Connection;
@@ -88,9 +86,7 @@ public interface JdbcCoordinator extends Serializable {
public void afterTransaction();
- public void coordinateWork(Work work);
-
- public T coordinateWork(ReturningWork work);
+ public T coordinateWork(WorkExecutorVisitable work);
public void executeBatch();
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jdbc/JdbcIsolationDelegate.java b/hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jdbc/JdbcIsolationDelegate.java
index 516b1f7287..be97d17a79 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jdbc/JdbcIsolationDelegate.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jdbc/JdbcIsolationDelegate.java
@@ -30,8 +30,8 @@ import org.hibernate.HibernateLogger;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.transaction.spi.IsolationDelegate;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
-import org.hibernate.jdbc.ReturningWork;
-import org.hibernate.jdbc.Work;
+import org.hibernate.jdbc.WorkExecutorVisitable;
+import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.jboss.logging.Logger;
@@ -59,7 +59,7 @@ public class JdbcIsolationDelegate implements IsolationDelegate {
}
@Override
- public void delegateWork(Work work, boolean transacted) throws HibernateException {
+ public T delegateWork(WorkExecutorVisitable work, boolean transacted) throws HibernateException {
boolean wasAutoCommit = false;
try {
// todo : should we use a connection proxy here?
@@ -72,69 +72,7 @@ public class JdbcIsolationDelegate implements IsolationDelegate {
}
}
- work.execute( connection );
-
- if ( transacted ) {
- connection.commit();
- }
- }
- catch ( Exception e ) {
- try {
- if ( transacted && !connection.isClosed() ) {
- connection.rollback();
- }
- }
- catch ( Exception ignore ) {
- LOG.unableToRollbackConnection(ignore);
- }
-
- if ( e instanceof HibernateException ) {
- throw (HibernateException) e;
- }
- else if ( e instanceof SQLException ) {
- throw sqlExceptionHelper().convert( (SQLException) e, "error performing isolated work" );
- }
- else {
- throw new HibernateException( "error performing isolated work", e );
- }
- }
- finally {
- if ( transacted && wasAutoCommit ) {
- try {
- connection.setAutoCommit( true );
- }
- catch ( Exception ignore ) {
- LOG.trace("was unable to reset connection back to auto-commit");
- }
- }
- try {
- connectionProvider().closeConnection( connection );
- }
- catch ( Exception ignore ) {
- LOG.unableToReleaseIsolatedConnection(ignore);
- }
- }
- }
- catch ( SQLException sqle ) {
- throw sqlExceptionHelper().convert( sqle, "unable to obtain isolated JDBC connection" );
- }
- }
-
- @Override
- public T delegateWork(ReturningWork work, boolean transacted) throws HibernateException {
- boolean wasAutoCommit = false;
- try {
- // todo : should we use a connection proxy here?
- Connection connection = connectionProvider().getConnection();
- try {
- if ( transacted ) {
- if ( connection.getAutoCommit() ) {
- wasAutoCommit = true;
- connection.setAutoCommit( false );
- }
- }
-
- T result = work.execute( connection );
+ T result = work.accept( new WorkExecutor(), connection );
if ( transacted ) {
connection.commit();
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jta/JtaIsolationDelegate.java b/hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jta/JtaIsolationDelegate.java
index 571669b867..5ff3b2f93c 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jta/JtaIsolationDelegate.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/transaction/internal/jta/JtaIsolationDelegate.java
@@ -34,8 +34,8 @@ import org.hibernate.HibernateLogger;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.transaction.spi.IsolationDelegate;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
-import org.hibernate.jdbc.ReturningWork;
-import org.hibernate.jdbc.Work;
+import org.hibernate.jdbc.WorkExecutorVisitable;
+import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.jboss.logging.Logger;
@@ -76,109 +76,7 @@ public class JtaIsolationDelegate implements IsolationDelegate {
}
@Override
- public void delegateWork(Work work, boolean transacted) throws HibernateException {
- TransactionManager transactionManager = transactionManager();
-
- try {
- // First we suspend any current JTA transaction
- Transaction surroundingTransaction = transactionManager.suspend();
- LOG.debugf("Surrounding JTA transaction suspended [%s]", surroundingTransaction);
-
- boolean hadProblems = false;
- try {
- // then perform the requested work
- if ( transacted ) {
- doTheWorkInNewTransaction( work, transactionManager );
- }
- else {
- doTheWorkInNoTransaction( work );
- }
- }
- catch ( HibernateException e ) {
- hadProblems = true;
- throw e;
- }
- finally {
- try {
- transactionManager.resume( surroundingTransaction );
- LOG.debugf("Surrounding JTA transaction resumed [%s]", surroundingTransaction);
- }
- catch( Throwable t ) {
- // if the actually work had an error use that, otherwise error based on t
- if ( !hadProblems ) {
- //noinspection ThrowFromFinallyBlock
- throw new HibernateException( "Unable to resume previously suspended transaction", t );
- }
- }
- }
- }
- catch ( SystemException e ) {
- throw new HibernateException( "Unable to suspend current JTA transaction", e );
- }
- }
-
- private void doTheWorkInNewTransaction(Work work, TransactionManager transactionManager) {
- try {
- // start the new isolated transaction
- transactionManager.begin();
-
- try {
- doTheWork( work );
- // if everythign went ok, commit the isolated transaction
- transactionManager.commit();
- }
- catch ( Exception e ) {
- try {
- transactionManager.rollback();
- }
- catch ( Exception ignore ) {
- LOG.unableToRollbackIsolatedTransaction(e, ignore);
- }
- }
- }
- catch ( SystemException e ) {
- throw new HibernateException( "Unable to start isolated transaction", e );
- }
- catch ( NotSupportedException e ) {
- throw new HibernateException( "Unable to start isolated transaction", e );
- }
- }
-
- private void doTheWorkInNoTransaction(Work work) {
- doTheWork( work );
- }
-
- private void doTheWork(Work work) {
- try {
- // obtain our isolated connection
- Connection connection = connectionProvider().getConnection();
- try {
- // do the actual work
- work.execute( connection );
- }
- catch ( HibernateException e ) {
- throw e;
- }
- catch ( Exception e ) {
- throw new HibernateException( "Unable to perform isolated work", e );
- }
- finally {
- try {
- // no matter what, release the connection (handle)
- connectionProvider().closeConnection( connection );
- }
- catch ( Throwable ignore ) {
- LOG.unableToReleaseIsolatedConnection(ignore);
- }
- }
- }
- catch ( SQLException sqle ) {
- throw sqlExceptionHelper().convert( sqle, "unable to obtain isolated JDBC connection" );
- }
- }
-
- @Override
- public T delegateWork(ReturningWork work, boolean transacted) throws HibernateException {
+ public T delegateWork(WorkExecutorVisitable work, boolean transacted) throws HibernateException {
TransactionManager transactionManager = transactionManager();
try {
@@ -203,7 +101,7 @@ public class JtaIsolationDelegate implements IsolationDelegate {
finally {
try {
transactionManager.resume( surroundingTransaction );
- LOG.debugf("Surrounding JTA transaction resumed [%s]", surroundingTransaction);
+ LOG.debugf( "Surrounding JTA transaction resumed [%s]", surroundingTransaction );
}
catch( Throwable t ) {
// if the actually work had an error use that, otherwise error based on t
@@ -219,7 +117,7 @@ public class JtaIsolationDelegate implements IsolationDelegate {
}
}
- private T doTheWorkInNewTransaction(ReturningWork work, TransactionManager transactionManager) {
+ private T doTheWorkInNewTransaction(WorkExecutorVisitable work, TransactionManager transactionManager) {
T result = null;
try {
// start the new isolated transaction
@@ -248,17 +146,17 @@ public class JtaIsolationDelegate implements IsolationDelegate {
return result;
}
- private T doTheWorkInNoTransaction(ReturningWork work) {
+ private T doTheWorkInNoTransaction(WorkExecutorVisitable work) {
return doTheWork( work );
}
- private T doTheWork(ReturningWork work) {
+ private T doTheWork(WorkExecutorVisitable work) {
try {
// obtain our isolated connection
Connection connection = connectionProvider().getConnection();
try {
// do the actual work
- return work.execute( connection );
+ return work.accept( new WorkExecutor(), connection );
}
catch ( HibernateException e ) {
throw e;
@@ -280,6 +178,5 @@ public class JtaIsolationDelegate implements IsolationDelegate {
throw sqlExceptionHelper().convert( e, "unable to obtain isolated JDBC connection" );
}
}
-
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/IsolationDelegate.java b/hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/IsolationDelegate.java
index e744b0d00a..2bed27d2f9 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/IsolationDelegate.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/transaction/spi/IsolationDelegate.java
@@ -24,8 +24,7 @@
package org.hibernate.engine.transaction.spi;
import org.hibernate.HibernateException;
-import org.hibernate.jdbc.ReturningWork;
-import org.hibernate.jdbc.Work;
+import org.hibernate.jdbc.WorkExecutorVisitable;
/**
* Contract for performing work in a manner that isolates it from any current transaction.
@@ -33,16 +32,6 @@ import org.hibernate.jdbc.Work;
* @author Steve Ebersole
*/
public interface IsolationDelegate {
- /**
- * Perform the given work in isolation from current transaction.
- *
- * @param work The work to be performed.
- * @param transacted Should the work itself be done in a (isolated) transaction?
- *
- * @throws HibernateException Indicates a problem performing the work.
- */
- public void delegateWork(Work work, boolean transacted) throws HibernateException;
-
/**
* Perform the given work in isolation from current transaction.
*
@@ -53,5 +42,5 @@ public interface IsolationDelegate {
*
* @throws HibernateException Indicates a problem performing the work.
*/
- public T delegateWork(ReturningWork work, boolean transacted) throws HibernateException;
+ public T delegateWork(WorkExecutorVisitable work, boolean transacted) throws HibernateException;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/hql/ast/exec/AbstractStatementExecutor.java b/hibernate-core/src/main/java/org/hibernate/hql/ast/exec/AbstractStatementExecutor.java
index 96d47adcf3..3098d400e4 100644
--- a/hibernate-core/src/main/java/org/hibernate/hql/ast/exec/AbstractStatementExecutor.java
+++ b/hibernate-core/src/main/java/org/hibernate/hql/ast/exec/AbstractStatementExecutor.java
@@ -40,7 +40,7 @@ import org.hibernate.event.EventSource;
import org.hibernate.hql.ast.HqlSqlWalker;
import org.hibernate.hql.ast.SqlGenerator;
import org.hibernate.internal.util.StringHelper;
-import org.hibernate.jdbc.Work;
+import org.hibernate.jdbc.AbstractWork;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.InsertSelect;
import org.hibernate.sql.Select;
@@ -137,7 +137,7 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
" from " + persister.getTemporaryIdTableName();
}
- private static class TemporaryTableCreationWork implements Work {
+ private static class TemporaryTableCreationWork extends AbstractWork {
private final Queryable persister;
private TemporaryTableCreationWork(Queryable persister) {
@@ -209,7 +209,7 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
}
};
- private static class TemporaryTableDropWork implements Work {
+ private static class TemporaryTableDropWork extends AbstractWork {
private final Queryable persister;
private final SessionImplementor session;
diff --git a/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java
index 390b9a1366..c4c86e7700 100644
--- a/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java
+++ b/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java
@@ -43,7 +43,8 @@ import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.id.enhanced.AccessCallback;
import org.hibernate.id.enhanced.OptimizerFactory;
import org.hibernate.internal.util.config.ConfigurationHelper;
-import org.hibernate.jdbc.ReturningWork;
+import org.hibernate.jdbc.AbstractReturningWork;
+import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.mapping.Table;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
@@ -147,7 +148,7 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
}
public synchronized Serializable generate(final SessionImplementor session, Object obj) {
- final ReturningWork work = new ReturningWork() {
+ final WorkExecutorVisitable work = new AbstractReturningWork() {
@Override
public IntegralDataTypeHolder execute(Connection connection) throws SQLException {
IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( returnClass );
diff --git a/hibernate-core/src/main/java/org/hibernate/id/TableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/TableGenerator.java
index a63d3d3416..cfe9a4104d 100644
--- a/hibernate-core/src/main/java/org/hibernate/id/TableGenerator.java
+++ b/hibernate-core/src/main/java/org/hibernate/id/TableGenerator.java
@@ -40,7 +40,7 @@ import org.hibernate.engine.jdbc.internal.FormatStyle;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.internal.util.config.ConfigurationHelper;
-import org.hibernate.jdbc.ReturningWork;
+import org.hibernate.jdbc.AbstractReturningWork;
import org.hibernate.mapping.Table;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
@@ -144,7 +144,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
.getService( JdbcServices.class )
.getSqlStatementLogger();
return session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork(
- new ReturningWork() {
+ new AbstractReturningWork() {
@Override
public IntegralDataTypeHolder execute(Connection connection) throws SQLException {
IntegralDataTypeHolder value = buildHolder();
diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java
index 845b1d7e06..5197d8e332 100644
--- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java
+++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java
@@ -50,7 +50,7 @@ import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
-import org.hibernate.jdbc.ReturningWork;
+import org.hibernate.jdbc.AbstractReturningWork;
import org.hibernate.mapping.Table;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
@@ -465,7 +465,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
@Override
public IntegralDataTypeHolder getNextValue() {
return session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork(
- new ReturningWork() {
+ new AbstractReturningWork() {
@Override
public IntegralDataTypeHolder execute(Connection connection) throws SQLException {
IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() );
diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java
index d7bdd3d084..b478ea3e61 100644
--- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java
+++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java
@@ -39,7 +39,7 @@ import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.id.IdentifierGenerationException;
import org.hibernate.id.IdentifierGeneratorHelper;
import org.hibernate.id.IntegralDataTypeHolder;
-import org.hibernate.jdbc.ReturningWork;
+import org.hibernate.jdbc.AbstractReturningWork;
import org.jboss.logging.Logger;
/**
@@ -115,7 +115,7 @@ public class TableStructure implements DatabaseStructure {
@Override
public IntegralDataTypeHolder getNextValue() {
return session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork(
- new ReturningWork() {
+ new AbstractReturningWork() {
@Override
public IntegralDataTypeHolder execute(Connection connection) throws SQLException {
final SqlStatementLogger statementLogger = session
diff --git a/hibernate-core/src/main/java/org/hibernate/impl/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/impl/SessionImpl.java
index 1b8429f9ee..4f9f196b3b 100644
--- a/hibernate-core/src/main/java/org/hibernate/impl/SessionImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/impl/SessionImpl.java
@@ -125,7 +125,10 @@ import org.hibernate.event.SaveOrUpdateEventListener;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
+import org.hibernate.jdbc.WorkExecutorVisitable;
+import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
+import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.loader.criteria.CriteriaLoader;
import org.hibernate.loader.custom.CustomLoader;
import org.hibernate.loader.custom.CustomQuery;
@@ -1975,8 +1978,29 @@ public final class SessionImpl
persistenceContext.setReadOnly(entity, readOnly);
}
- public void doWork(Work work) throws HibernateException {
- transactionCoordinator.getJdbcCoordinator().coordinateWork( work );
+ public void doWork(final Work work) throws HibernateException {
+ WorkExecutorVisitable realWork = new WorkExecutorVisitable() {
+ @Override
+ public Void accept(WorkExecutor workExecutor, Connection connection) throws SQLException {
+ workExecutor.executeWork( work, connection );
+ return null;
+ }
+ };
+ doWork( realWork );
+ }
+
+ public T doReturningWork(final ReturningWork work) throws HibernateException {
+ WorkExecutorVisitable realWork = new WorkExecutorVisitable() {
+ @Override
+ public T accept(WorkExecutor workExecutor, Connection connection) throws SQLException {
+ return workExecutor.executeReturningWork( work, connection );
+ }
+ };
+ return doWork( realWork );
+ }
+
+ private T doWork(WorkExecutorVisitable work) throws HibernateException {
+ return transactionCoordinator.getJdbcCoordinator().coordinateWork( work );
}
public void afterScrollOperation() {
diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/AbstractReturningWork.java b/hibernate-core/src/main/java/org/hibernate/jdbc/AbstractReturningWork.java
new file mode 100644
index 0000000000..d7d1191c6e
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/jdbc/AbstractReturningWork.java
@@ -0,0 +1,53 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jdbc;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * An abstract implementation of {@link ReturningWork} that accepts a {@link WorkExecutor}
+ * visitor for executing a discrete piece of work and returning a result.
+ *
+ * This class is intended to be used for work that returns a value when executed.
+ *
+ * @author Gail Badner
+ */
+public abstract class AbstractReturningWork implements ReturningWork, WorkExecutorVisitable {
+ /**
+ * Accepts a {@link WorkExecutor} visitor for executing the discrete work
+ * encapsulated by this work instance using the supplied connection.
+ *
+ * @param executor The visitor that executes the work
+ * @param connection The connection on which to perform the work.
+ *
+ * @return the valued returned by {@link #execute(java.sql.Connection)}.
+ *
+ * @throws SQLException Thrown during execution of the underlying JDBC interaction.
+ * @throws org.hibernate.HibernateException Generally indicates a wrapped SQLException.
+ */
+ public T accept(WorkExecutor executor, Connection connection) throws SQLException {
+ return executor.executeReturningWork( this, connection );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/AbstractWork.java b/hibernate-core/src/main/java/org/hibernate/jdbc/AbstractWork.java
new file mode 100644
index 0000000000..22c6d20f7b
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/jdbc/AbstractWork.java
@@ -0,0 +1,57 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jdbc;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * An abstract implementation of {@link Work} that accepts a {@link WorkExecutor}
+ * visitor for executing a discrete piece of work.
+ *
+ * This class is intended to be used for work that does not return a value when
+ * executed.
+ *
+ * @author Gail Badner
+ */
+public abstract class AbstractWork implements Work, WorkExecutorVisitable {
+ /**
+ * Accepts a {@link WorkExecutor} visitor for executing the discrete work
+ * encapsulated by this work instance using the supplied connection.
+ *
+ * Because {@link Work} does not return a value when executed
+ * (via {@link Work#execute(java.sql.Connection)}, this method
+ * always returns null.
+ *
+ * @param connection The connection on which to perform the work.
+ *
+ * @return null
+ *
+ * @throws SQLException Thrown during execution of the underlying JDBC interaction.
+ * @throws org.hibernate.HibernateException Generally indicates a wrapped SQLException.
+ */
+ public Void accept(WorkExecutor executor, Connection connection) throws SQLException {
+ return executor.executeWork( this, connection );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/WorkExecutor.java b/hibernate-core/src/main/java/org/hibernate/jdbc/WorkExecutor.java
new file mode 100644
index 0000000000..ba2d6b3b6c
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/jdbc/WorkExecutor.java
@@ -0,0 +1,74 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jdbc;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * A visitor used for executing a discrete piece of work encapsulated in a
+ * {@link Work} or {@link ReturningWork} instance..
+ *
+ * @author Gail Badner
+ */
+public class WorkExecutor {
+
+ /**
+ * Execute the discrete work encapsulated by a {@link Work} instance
+ * using the supplied connection.
+ *
+ * Because {@link Work} does not return a value when executed
+ * (via {@link Work#execute(java.sql.Connection)}, this method
+ * always returns null.
+ *
+ * @param work The @link ReturningWork} instance encapsulating the discrete work
+ * @param connection The connection on which to perform the work.
+ *
+ * @return null>.
+ *
+ * @throws SQLException Thrown during execution of the underlying JDBC interaction.
+ * @throws org.hibernate.HibernateException Generally indicates a wrapped SQLException.
+ */
+ public T executeWork(Work work, Connection connection) throws SQLException {
+ work.execute( connection );
+ return null;
+ }
+
+ /**
+ * Execute the discrete work encapsulated by a {@link ReturningWork} instance
+ * using the supplied connection, returning the result of
+ * {@link ReturningWork#execute(java.sql.Connection)}
+ *
+ * @param work The @link ReturningWork} instance encapsulating the discrete work
+ * @param connection The connection on which to perform the work.
+ *
+ * @return the valued returned by work.execute(connection)
.
+ *
+ * @throws SQLException Thrown during execution of the underlying JDBC interaction.
+ * @throws org.hibernate.HibernateException Generally indicates a wrapped SQLException.
+ */
+ public T executeReturningWork(ReturningWork work, Connection connection) throws SQLException {
+ return work.execute( connection );
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/jdbc/WorkExecutorVisitable.java b/hibernate-core/src/main/java/org/hibernate/jdbc/WorkExecutorVisitable.java
new file mode 100644
index 0000000000..e6f5c2d391
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/jdbc/WorkExecutorVisitable.java
@@ -0,0 +1,53 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.jdbc;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * This interface provides a way to execute unrelated "work" objects using
+ * polymorphism.
+ *
+ * Instances of this interface can accept a {@link WorkExecutor} visitor
+ * for executing a discrete piece of work, and return an implementation-defined
+ * result.
+ *
+ * @author Gail Badner
+ */
+public interface WorkExecutorVisitable {
+ /**
+ * Accepts a {@link WorkExecutor} visitor for executing a discrete
+ * piece of work, and returns an implementation-defined result..
+ *
+ * @param executor The visitor that executes the work.
+ * @param connection The connection on which to perform the work.
+ *
+ * @return an implementation-defined result
+ *
+ * @throws SQLException Thrown during execution of the underlying JDBC interaction.
+ * @throws org.hibernate.HibernateException Generally indicates a wrapped SQLException.
+ */
+ public T accept(WorkExecutor executor, Connection connection) throws SQLException;
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/jdbc/GeneralWorkTest.java b/hibernate-core/src/test/java/org/hibernate/test/jdbc/GeneralWorkTest.java
index c0379391fb..acb1648090 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/jdbc/GeneralWorkTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/jdbc/GeneralWorkTest.java
@@ -21,6 +21,7 @@ import java.sql.Statement;
import junit.framework.Test;
import org.hibernate.JDBCException;
import org.hibernate.Session;
+import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.testing.junit.functional.FunctionalTestCase;
import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite;
@@ -108,6 +109,52 @@ public class GeneralWorkTest extends FunctionalTestCase {
session.close();
}
+ public void testGeneralReturningUsage() throws Throwable {
+ Session session = openSession();
+ session.beginTransaction();
+ Person p = new Person( "Abe", "Lincoln" );
+ session.save( p );
+ session.getTransaction().commit();
+
+ session = openSession();
+ session.beginTransaction();
+ long count = session.doReturningWork(
+ new ReturningWork() {
+ public Long execute(Connection connection) throws SQLException {
+ // in this current form, users must handle try/catches themselves for proper resource release
+ Statement statement = null;
+ long personCount = 0;
+ try {
+ statement = connection.createStatement();
+ ResultSet resultSet = null;
+ try {
+ resultSet = statement.executeQuery( "select count(*) from T_JDBC_PERSON" );
+ resultSet.next();
+ personCount = resultSet.getLong( 1 );
+ assertEquals( 1L, personCount );
+ }
+ finally {
+ releaseQuietly( resultSet );
+ }
+ }
+ finally {
+ releaseQuietly( statement );
+ }
+ return personCount;
+ }
+ }
+ );
+ session.getTransaction().commit();
+ session.close();
+ assertEquals( 1L, count );
+
+ session = openSession();
+ session.beginTransaction();
+ session.delete( p );
+ session.getTransaction().commit();
+ session.close();
+ }
+
private void releaseQuietly(Statement statement) {
if ( statement == null ) {
return;