[hibernate-commits] Hibernate SVN: r19962 - in core/trunk: core/src/main/java/org/hibernate/jdbc and 4 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Fri Jul 16 15:04:27 EDT 2010


Author: steve.ebersole at jboss.com
Date: 2010-07-16 15:04:26 -0400 (Fri, 16 Jul 2010)
New Revision: 19962

Added:
   core/trunk/core/src/main/java/org/hibernate/engine/transaction/NullSynchronizationException.java
   core/trunk/core/src/main/java/org/hibernate/engine/transaction/SynchronizationRegistry.java
   core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/
   core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/AfterCompletionAction.java
   core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/BeforeCompletionManagedFlushChecker.java
   core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/CallbackCoordinator.java
   core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/ExceptionMapper.java
   core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/HibernateSynchronizationImpl.java
Modified:
   core/trunk/core/src/main/java/org/hibernate/jdbc/JDBCContext.java
   core/trunk/core/src/main/java/org/hibernate/transaction/JDBCTransaction.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
   core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java
   core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java
Log:
HHH-5384 - HEM should not register its own Synchronization


Added: core/trunk/core/src/main/java/org/hibernate/engine/transaction/NullSynchronizationException.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/transaction/NullSynchronizationException.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/engine/transaction/NullSynchronizationException.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -0,0 +1,41 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, 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.engine.transaction;
+
+import org.hibernate.HibernateException;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class NullSynchronizationException extends HibernateException {
+	public NullSynchronizationException() {
+		this( "Synchronization to register cannot be null" );
+	}
+
+	public NullSynchronizationException(String s) {
+		super( s );
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/engine/transaction/SynchronizationRegistry.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/transaction/SynchronizationRegistry.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/engine/transaction/SynchronizationRegistry.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -0,0 +1,101 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, 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.engine.transaction;
+
+import java.util.LinkedHashSet;
+import javax.transaction.Synchronization;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Manages a registry of {@link Synchronization Synchronizations}.
+ *
+ * @author Steve Ebersole
+ */
+public class SynchronizationRegistry {
+	private static final Logger log = LoggerFactory.getLogger( SynchronizationRegistry.class );
+
+	private LinkedHashSet<Synchronization> synchronizations;
+
+	/**
+	 * Register a user {@link Synchronization} callback for this transaction.
+	 *
+	 * @param synchronization The synchronization callback to register.
+	 * 
+	 * @throws HibernateException
+	 */
+	public void registerSynchronization(Synchronization synchronization) {
+		if ( synchronization == null ) {
+			throw new NullSynchronizationException();
+		}
+
+		if ( synchronizations == null ) {
+			synchronizations = new LinkedHashSet<Synchronization>();
+		}
+
+		boolean added = synchronizations.add( synchronization );
+		if ( !added ) {
+			log.info( "Synchronization [{}] was already registered", synchronization );
+		}
+	}
+
+	/**
+	 * Delegate {@link Synchronization#beforeCompletion} calls to {@link #registerSynchronization registered}
+	 * {@link Synchronization Synchronizations}
+	 */
+	public void notifySynchronizationsBeforeTransactionCompletion() {
+		if ( synchronizations != null ) {
+			for ( Synchronization synchronization : synchronizations ) {
+				try {
+					synchronization.beforeCompletion();
+				}
+				catch ( Throwable t ) {
+					log.error( "exception calling user Synchronization [{}]", synchronization, t );
+				}
+			}
+		}
+	}
+
+	/**
+	 * Delegate {@link Synchronization#afterCompletion} calls to {@link #registerSynchronization registered}
+	 * {@link Synchronization Synchronizations}
+	 *
+	 * @param status The transaction status (if known) per {@link javax.transaction.Status}
+	 */
+	public void notifySynchronizationsAfterTransactionCompletion(int status) {
+		if ( synchronizations != null ) {
+			for ( Synchronization synchronization : synchronizations ) {
+				try {
+					synchronization.afterCompletion( status );
+				}
+				catch ( Throwable t ) {
+					log.error( "exception calling user Synchronization [{}]", synchronization, t );
+				}
+			}
+		}
+	}
+}

Modified: core/trunk/core/src/main/java/org/hibernate/jdbc/JDBCContext.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/jdbc/JDBCContext.java	2010-07-16 15:27:49 UTC (rev 19961)
+++ core/trunk/core/src/main/java/org/hibernate/jdbc/JDBCContext.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -41,6 +41,8 @@
 import org.hibernate.SessionException;
 import org.hibernate.Transaction;
 import org.hibernate.TransactionException;
+import org.hibernate.transaction.synchronization.CallbackCoordinator;
+import org.hibernate.transaction.synchronization.HibernateSynchronizationImpl;
 import org.hibernate.util.JTAHelper;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.exception.JDBCExceptionHelper;
@@ -82,6 +84,8 @@
 	private transient boolean isTransactionCallbackRegistered;
 	private transient Transaction hibernateTransaction;
 
+	private CallbackCoordinator jtaSynchronizationCallbackCoordinator;
+
 	public JDBCContext(Context owner, Connection connection, Interceptor interceptor) {
 		this.owner = owner;
 		this.connectionManager = new ConnectionManager(
@@ -107,6 +111,20 @@
 	private JDBCContext() {
 	}
 
+	public CallbackCoordinator getJtaSynchronizationCallbackCoordinator() {
+		return jtaSynchronizationCallbackCoordinator;
+	}
+
+	public CallbackCoordinator getJtaSynchronizationCallbackCoordinator(javax.transaction.Transaction jtaTransaction) {
+		jtaSynchronizationCallbackCoordinator = new CallbackCoordinator( owner, this, jtaTransaction, hibernateTransaction );
+		return jtaSynchronizationCallbackCoordinator;
+	}
+
+	public void cleanUpJtaSynchronizationCallbackCoordinator() {
+		jtaSynchronizationCallbackCoordinator = null;
+	}
+
+
 	// ConnectionManager.Callback implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 	public void connectionOpened() {
@@ -194,7 +212,10 @@
 						if ( hibernateTransaction == null ) {
 							hibernateTransaction = owner.getFactory().getSettings().getTransactionFactory().createTransaction( this, owner );
 						}
-						tx.registerSynchronization( new CacheSynchronization(owner, this, tx, hibernateTransaction) );
+						tx.registerSynchronization(
+								new HibernateSynchronizationImpl( getJtaSynchronizationCallbackCoordinator( tx ) )
+						);
+//						tx.registerSynchronization( new CacheSynchronization(owner, this, tx, hibernateTransaction) );
 						isTransactionCallbackRegistered = true;
 						log.debug("successfully registered Synchronization");
 						return true;

Modified: core/trunk/core/src/main/java/org/hibernate/transaction/JDBCTransaction.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/transaction/JDBCTransaction.java	2010-07-16 15:27:49 UTC (rev 19961)
+++ core/trunk/core/src/main/java/org/hibernate/transaction/JDBCTransaction.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -1,10 +1,10 @@
 /*
  * Hibernate, Relational Persistence for Idiomatic Java
  *
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, 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 Middleware LLC.
+ * 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
@@ -20,13 +20,10 @@
  * Free Software Foundation, Inc.
  * 51 Franklin Street, Fifth Floor
  * Boston, MA  02110-1301  USA
- *
  */
 package org.hibernate.transaction;
 
 import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
 import javax.transaction.Status;
 import javax.transaction.Synchronization;
 
@@ -36,11 +33,11 @@
 import org.hibernate.HibernateException;
 import org.hibernate.Transaction;
 import org.hibernate.TransactionException;
+import org.hibernate.engine.transaction.SynchronizationRegistry;
 import org.hibernate.jdbc.JDBCContext;
 
 /**
- * {@link Transaction} implementation based on transaction management through
- * a JDBC {@link java.sql.Connection}.
+ * {@link Transaction} implementation based on transaction management through a JDBC {@link java.sql.Connection}.
  * <p/>
  * This the Hibernate's default transaction strategy.
  *
@@ -48,9 +45,9 @@
  * @author Gavin King
  */
 public class JDBCTransaction implements Transaction {
-
 	private static final Logger log = LoggerFactory.getLogger(JDBCTransaction.class);
 
+	private final SynchronizationRegistry synchronizationRegistry = new SynchronizationRegistry();
 	private final JDBCContext jdbcContext;
 	private final TransactionFactory.Context transactionContext;
 
@@ -59,7 +56,6 @@
 	private boolean rolledBack;
 	private boolean committed;
 	private boolean commitFailed;
-	private List synchronizations;
 	private boolean callback;
 	private int timeout = -1;
 
@@ -137,7 +133,7 @@
 			transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
 		}
 
-		notifyLocalSynchsBeforeTransactionCompletion();
+		notifySynchronizationsBeforeTransactionCompletion();
 		if ( callback ) {
 			jdbcContext.beforeTransactionCompletion( this );
 		}
@@ -149,7 +145,7 @@
 			if ( callback ) {
 				jdbcContext.afterTransactionCompletion( true, this );
 			}
-			notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_COMMITTED );
+			notifySynchronizationsAfterTransactionCompletion( Status.STATUS_COMMITTED );
 		}
 		catch (SQLException e) {
 			log.error("JDBC commit failed", e);
@@ -157,7 +153,7 @@
 			if ( callback ) {
 				jdbcContext.afterTransactionCompletion( false, this );
 			}
-			notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_UNKNOWN );
+			notifySynchronizationsAfterTransactionCompletion( Status.STATUS_UNKNOWN );
 			throw new TransactionException("JDBC commit failed", e);
 		}
 		finally {
@@ -196,11 +192,11 @@
 				rollbackAndResetAutoCommit();
 				log.debug("rolled back JDBC Connection");
 				rolledBack = true;
-				notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_ROLLEDBACK);
+				notifySynchronizationsAfterTransactionCompletion(Status.STATUS_ROLLEDBACK);
 			}
 			catch (SQLException e) {
 				log.error("JDBC rollback failed", e);
-				notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_UNKNOWN);
+				notifySynchronizationsAfterTransactionCompletion(Status.STATUS_UNKNOWN);
 				throw new TransactionException("JDBC rollback failed", e);
 			}
 			finally {
@@ -258,41 +254,17 @@
 	/**
 	 * {@inheritDoc}
 	 */
-	public void registerSynchronization(Synchronization sync) throws HibernateException {
-		if (sync==null) throw new NullPointerException("null Synchronization");
-		if (synchronizations==null) {
-			synchronizations = new ArrayList();
-		}
-		synchronizations.add(sync);
+	public void registerSynchronization(Synchronization sync) {
+		synchronizationRegistry.registerSynchronization( sync );
 	}
 
-	private void notifyLocalSynchsBeforeTransactionCompletion() {
-		if (synchronizations!=null) {
-			for ( int i=0; i<synchronizations.size(); i++ ) {
-				Synchronization sync = (Synchronization) synchronizations.get(i);
-				try {
-					sync.beforeCompletion();
-				}
-				catch (Throwable t) {
-					log.error("exception calling user Synchronization", t);
-				}
-			}
-		}
+	private void notifySynchronizationsBeforeTransactionCompletion() {
+		synchronizationRegistry.notifySynchronizationsBeforeTransactionCompletion();
 	}
 
-	private void notifyLocalSynchsAfterTransactionCompletion(int status) {
+	private void notifySynchronizationsAfterTransactionCompletion(int status) {
 		begun = false;
-		if (synchronizations!=null) {
-			for ( int i=0; i<synchronizations.size(); i++ ) {
-				Synchronization sync = (Synchronization) synchronizations.get(i);
-				try {
-					sync.afterCompletion(status);
-				}
-				catch (Throwable t) {
-					log.error("exception calling user Synchronization", t);
-				}
-			}
-		}
+		synchronizationRegistry.notifySynchronizationsAfterTransactionCompletion( status );
 	}
 
 	/**

Added: core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/AfterCompletionAction.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/AfterCompletionAction.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/AfterCompletionAction.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -0,0 +1,35 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, 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.transaction.synchronization;
+
+import org.hibernate.transaction.TransactionFactory;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public interface AfterCompletionAction {
+	public void doAction(TransactionFactory.Context ctx, int status);
+}

Added: core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/BeforeCompletionManagedFlushChecker.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/BeforeCompletionManagedFlushChecker.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/BeforeCompletionManagedFlushChecker.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -0,0 +1,51 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, 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.transaction.synchronization;
+
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+
+import org.hibernate.transaction.TransactionFactory;
+
+/**
+ * Contract for checking whether to perform a managed flush in a
+ * {@link javax.transaction.Synchronization#beforeCompletion()} callback
+ *
+ * @author Steve Ebersole
+ */
+public interface BeforeCompletionManagedFlushChecker {
+	/**
+	 * Check whether we should perform the managed flush
+	 *
+	 * @param ctx The Hibernate "transaction context"
+	 * @param jtaTransaction The JTA transaction
+	 *
+	 * @return True to indicate to perform the managed flush; false otherwise.
+	 *
+	 * @throws SystemException Can be thrown while accessing the JTA transaction; will result in transaction being
+	 * marked for rollback (best effort).
+	 */
+	public boolean shouldDoManagedFlush(TransactionFactory.Context ctx, Transaction jtaTransaction)
+			throws SystemException;
+}

Added: core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/CallbackCoordinator.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/CallbackCoordinator.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/CallbackCoordinator.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -0,0 +1,186 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, 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.transaction.synchronization;
+
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.TransactionException;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.transaction.TransactionFactory;
+import org.hibernate.util.JTAHelper;
+
+/**
+ * Manages callbacks from the {@link javax.transaction.Synchronization} registered by Hibernate.
+ *
+ * @author Steve Ebersole
+ */
+public class CallbackCoordinator {
+	private static final Logger log = LoggerFactory.getLogger( CallbackCoordinator.class );
+
+	private final TransactionFactory.Context ctx;
+	private JDBCContext jdbcContext;
+	private final Transaction jtaTransaction;
+	private final org.hibernate.Transaction hibernateTransaction;
+
+	private BeforeCompletionManagedFlushChecker beforeCompletionManagedFlushChecker;
+	private AfterCompletionAction afterCompletionAction;
+	private ExceptionMapper exceptionMapper;
+
+	public CallbackCoordinator(
+			TransactionFactory.Context ctx,
+			JDBCContext jdbcContext,
+			Transaction jtaTransaction,
+			org.hibernate.Transaction hibernateTransaction) {
+		this.ctx = ctx;
+		this.jdbcContext = jdbcContext;
+		this.jtaTransaction = jtaTransaction;
+		this.hibernateTransaction = hibernateTransaction;
+		reset();
+	}
+
+	public void reset() {
+		beforeCompletionManagedFlushChecker = STANDARD_MANAGED_FLUSH_CHECKER;
+		exceptionMapper = STANDARD_EXCEPTION_MAPPER;
+		afterCompletionAction = STANDARD_AFTER_COMPLETION_ACTION;
+	}
+
+	public BeforeCompletionManagedFlushChecker getBeforeCompletionManagedFlushChecker() {
+		return beforeCompletionManagedFlushChecker;
+	}
+
+	public void setBeforeCompletionManagedFlushChecker(BeforeCompletionManagedFlushChecker beforeCompletionManagedFlushChecker) {
+		this.beforeCompletionManagedFlushChecker = beforeCompletionManagedFlushChecker;
+	}
+
+	public ExceptionMapper getExceptionMapper() {
+		return exceptionMapper;
+	}
+
+	public void setExceptionMapper(ExceptionMapper exceptionMapper) {
+		this.exceptionMapper = exceptionMapper;
+	}
+
+	public AfterCompletionAction getAfterCompletionAction() {
+		return afterCompletionAction;
+	}
+
+	public void setAfterCompletionAction(AfterCompletionAction afterCompletionAction) {
+		this.afterCompletionAction = afterCompletionAction;
+	}
+
+
+	// sync callbacks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public void beforeCompletion() {
+		log.trace( "transaction before completion callback" );
+
+		boolean flush;
+		try {
+			flush = beforeCompletionManagedFlushChecker.shouldDoManagedFlush( ctx, jtaTransaction );
+		}
+		catch ( SystemException se ) {
+			setRollbackOnly();
+			throw exceptionMapper.mapStatusCheckFailure( "could not determine transaction status in beforeCompletion()", se );
+		}
+
+		try {
+			if ( flush ) {
+				log.trace( "automatically flushing session" );
+				ctx.managedFlush();
+			}
+		}
+		catch ( RuntimeException re ) {
+			setRollbackOnly();
+			throw exceptionMapper.mapManagedFlushFailure( "error during managed flush", re );
+		}
+		finally {
+			jdbcContext.beforeTransactionCompletion( hibernateTransaction );
+		}
+	}
+
+	private void setRollbackOnly() {
+		try {
+			jtaTransaction.setRollbackOnly();
+		}
+		catch ( SystemException se ) {
+			// best effort
+			log.error( "could not set transaction to rollback only", se );
+		}
+	}
+
+	public void afterCompletion(int status) {
+		log.trace( "transaction after completion callback [status={}]", status );
+
+		try {
+			afterCompletionAction.doAction( ctx, status );
+
+			final boolean wasSuccessful = ( status == Status.STATUS_COMMITTED );
+			jdbcContext.afterTransactionCompletion( wasSuccessful, hibernateTransaction );
+		}
+		finally {
+			reset();
+			jdbcContext.cleanUpJtaSynchronizationCallbackCoordinator();
+			if ( ctx.shouldAutoClose() && !ctx.isClosed() ) {
+				log.trace( "automatically closing session" );
+				ctx.managedClose();
+			}
+		}
+	}
+
+	private static final BeforeCompletionManagedFlushChecker STANDARD_MANAGED_FLUSH_CHECKER = new BeforeCompletionManagedFlushChecker() {
+		public boolean shouldDoManagedFlush(TransactionFactory.Context ctx, Transaction jtaTransaction)
+				throws SystemException {
+			return !ctx.isFlushModeNever() &&
+					ctx.isFlushBeforeCompletionEnabled() &&
+			        !JTAHelper.isRollback( jtaTransaction.getStatus() );
+					//actually, this last test is probably unnecessary, since
+					//beforeCompletion() doesn't get called during rollback
+		}
+	};
+
+	private static final ExceptionMapper STANDARD_EXCEPTION_MAPPER = new ExceptionMapper() {
+		public RuntimeException mapStatusCheckFailure(String message, SystemException systemException) {
+			log.error( "could not determine transaction status [{}]", systemException.getMessage() );
+			return new TransactionException( "could not determine transaction status in beforeCompletion()", systemException );
+		}
+
+		public RuntimeException mapManagedFlushFailure(String message, RuntimeException failure) {
+			log.error( "Error during managed flush [{}]", failure.getMessage() );
+			return failure;
+		}
+	};
+
+	private static final AfterCompletionAction STANDARD_AFTER_COMPLETION_ACTION = new AfterCompletionAction() {
+		public void doAction(TransactionFactory.Context ctx, int status) {
+			// nothing to do by default.
+		}
+	};
+}

Added: core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/ExceptionMapper.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/ExceptionMapper.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/ExceptionMapper.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -0,0 +1,53 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, 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.transaction.synchronization;
+
+import javax.transaction.SystemException;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public interface ExceptionMapper {
+	/**
+	 * Map a JTA {@link SystemException} to the appropriate runtime-based exception.
+	 *
+	 * @param message The message to use for the returned exception
+	 * @param systemException The causal exception
+	 *
+	 * @return The appropriate exception to throw
+	 */
+	public RuntimeException mapStatusCheckFailure(String message, SystemException systemException);
+
+	/**
+	 * Map an exception encountered during a managed flush to the appropriate runtime-based exception.
+	 *
+	 * @param message The message to use for the returned exception
+	 * @param failure The causal exception
+	 *
+	 * @return The appropriate exception to throw
+	 */
+	public RuntimeException mapManagedFlushFailure(String message, RuntimeException failure);
+}

Added: core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/HibernateSynchronizationImpl.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/HibernateSynchronizationImpl.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/transaction/synchronization/HibernateSynchronizationImpl.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -0,0 +1,61 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, 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.transaction.synchronization;
+
+import javax.transaction.Synchronization;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link Synchronization} implementation Hibernate registers with the JTA {@link javax.transaction.Transaction}
+ *
+ * @author Gavin King
+ * @author Steve Ebersole
+ */
+public class HibernateSynchronizationImpl implements Synchronization {
+	private static final Logger log = LoggerFactory.getLogger( HibernateSynchronizationImpl.class );
+
+	private final CallbackCoordinator coordinator;
+
+	public HibernateSynchronizationImpl(CallbackCoordinator coordinator) {
+		this.coordinator = coordinator;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public void beforeCompletion() {
+		log.trace( "JTA sync : beforeCompletion()" );
+		coordinator.beforeCompletion();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public void afterCompletion(int status) {
+		log.trace( "JTA sync : afterCompletion({})", status );
+		coordinator.afterCompletion( status );
+	}
+}

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java	2010-07-16 15:27:49 UTC (rev 19961)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -101,6 +101,10 @@
 import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
 import org.hibernate.proxy.HibernateProxy;
 import org.hibernate.transaction.TransactionFactory;
+import org.hibernate.transaction.synchronization.AfterCompletionAction;
+import org.hibernate.transaction.synchronization.BeforeCompletionManagedFlushChecker;
+import org.hibernate.transaction.synchronization.CallbackCoordinator;
+import org.hibernate.transaction.synchronization.ExceptionMapper;
 import org.hibernate.transform.BasicTransformerAdapter;
 import org.hibernate.util.JTAHelper;
 import org.hibernate.util.ReflectHelper;
@@ -1017,73 +1021,31 @@
 					//flush before completion and
 					//register clear on rollback
 					log.trace( "Adding flush() and close() synchronization" );
-					joinableCMTTransaction.registerSynchronization(
-							new Synchronization() {
-								public void beforeCompletion() {
-									boolean flush = false;
-									TransactionFactory.Context ctx = null;
-									try {
-										ctx = ( TransactionFactory.Context ) session;
-										JoinableCMTTransaction joinable = ( JoinableCMTTransaction ) session.getTransaction();
-										javax.transaction.Transaction transaction = joinable.getTransaction();
-										if ( transaction == null ) {
-											log.warn(
-													"Transaction not available on beforeCompletionPhase: assuming valid"
-											);
-										}
-										flush = !ctx.isFlushModeNever() &&
-												//ctx.isFlushBeforeCompletionEnabled() &&
-												//TODO probably make it ! isFlushBeforecompletion()
-												( transaction == null || !JTAHelper.isRollback( transaction.getStatus() ) );
-										//transaction == null workaround a JBoss TMBug
+					CallbackCoordinator callbackCoordinator = ( (SessionImplementor ) getSession() ).getJDBCContext().getJtaSynchronizationCallbackCoordinator();
+					if ( callbackCoordinator == null ) {
+						throw new AssertionFailure( "Expecting CallbackCoordinator to be non-null" );
+					}
+					callbackCoordinator.setBeforeCompletionManagedFlushChecker(
+							new BeforeCompletionManagedFlushChecker() {
+								public boolean shouldDoManagedFlush(TransactionFactory.Context ctx, javax.transaction.Transaction jtaTransaction)
+										throws SystemException {
+									if ( transaction == null ) {
+										log.warn( "Transaction not available on beforeCompletion: assuming valid" );
 									}
-									catch ( SystemException se ) {
-										log.error( "could not determine transaction status", se );
-										PersistenceException pe = new PersistenceException(
-												"could not determine transaction status in beforeCompletion()",
-												se
-										);
-										// handlePersistenceException will mark the transaction as rollbacked
-										handlePersistenceException( pe );
-										throw pe;
-									}
-									catch ( HibernateException he ) {
-										throwPersistenceException( he );
-									}
-
-									try {
-										if ( flush ) {
-											log.trace( "automatically flushing session" );
-											ctx.managedFlush();
-										}
-										else {
-											log.trace( "skipping managed flushing" );
-										}
-									}
-									catch ( HibernateException he ) {
-										throw convert( he );
-									}
-									catch ( PersistenceException pe ) {
-										handlePersistenceException( pe );
-										throw pe;
-									}
-									catch ( RuntimeException re ) {
-										PersistenceException wrapped = new PersistenceException( re );
-										handlePersistenceException( wrapped );
-										throw wrapped;
-									}
+									return !ctx.isFlushModeNever()
+											&& ( jtaTransaction == null || !JTAHelper.isRollback( jtaTransaction.getStatus() ) );
 								}
-
-								public void afterCompletion(int status) {
+							}
+					);
+					callbackCoordinator.setAfterCompletionAction(
+							new AfterCompletionAction() {
+								public void doAction(TransactionFactory.Context ctx, int status) {
 									try {
-										if ( Status.STATUS_ROLLEDBACK == status
-												&& transactionType == PersistenceUnitTransactionType.JTA ) {
-											if ( session.isOpen() ) {
+										if ( !ctx.isClosed() ) {
+											if ( Status.STATUS_ROLLEDBACK == status
+													&& transactionType == PersistenceUnitTransactionType.JTA ) {
 												session.clear();
 											}
-										}
-										if ( session.isOpen() ) {
-											//only reset if the session is opened since you can't get the Transaction otherwise
 											JoinableCMTTransaction joinable = ( JoinableCMTTransaction ) session.getTransaction();
 											joinable.resetStatus();
 										}
@@ -1094,6 +1056,23 @@
 								}
 							}
 					);
+					callbackCoordinator.setExceptionMapper(
+							new ExceptionMapper() {
+								public RuntimeException mapStatusCheckFailure(String message, SystemException systemException) {
+									throw new PersistenceException( message, systemException );
+								}
+
+								public RuntimeException mapManagedFlushFailure(String message, RuntimeException failure) {
+									if ( HibernateException.class.isInstance( failure ) ) {
+										throw convert( failure );
+									}
+									if ( PersistenceException.class.isInstance( failure ) ) {
+										throw failure;
+									}
+									throw new PersistenceException( message, failure );
+								}
+							}
+					);
 				}
 				else {
 					log.warn( "Cannot join transaction: do not override {}", Environment.TRANSACTION_STRATEGY );

Modified: core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java	2010-07-16 15:27:49 UTC (rev 19961)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -1,10 +1,10 @@
 /*
  * Hibernate, Relational Persistence for Idiomatic Java
  *
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, 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 Middleware LLC.
+ * 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
@@ -37,12 +37,10 @@
 import org.hibernate.FlushMode;
 import org.hibernate.Session;
 
-import javax.transaction.Synchronization;
-
 /**
  * @author Adam Warski (adam at warski dot org)
  */
-public class AuditProcess implements BeforeTransactionCompletionProcess, Synchronization {
+public class AuditProcess implements BeforeTransactionCompletionProcess {
     private final RevisionInfoGenerator revisionInfoGenerator;
     private final SessionImplementor session;
 
@@ -157,12 +155,4 @@
             session.flush();
         }
     }
-
-    // Synchronization methods
-
-    public void beforeCompletion() {
-        doBeforeTransactionCompletion(session);
-    }
-
-    public void afterCompletion(int status) { }
 }

Modified: core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java	2010-07-16 15:27:49 UTC (rev 19961)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java	2010-07-16 19:04:26 UTC (rev 19962)
@@ -55,18 +55,7 @@
             auditProcess = new AuditProcess(revisionInfoGenerator, session);
             auditProcesses.put(transaction, auditProcess);
 
-            /*
-             * HHH-5315: the process must be both a BeforeTransactionCompletionProcess and a TX Synchronization.
-             *
-             * In a resource-local tx env, the process is called after the flush, and populates the audit tables.
-             * Also, any exceptions that occur during that are propagated (if a Synchronization was used, the exceptions
-             * would be eaten).
-             *
-             * In a JTA env, the before transaction completion is called before the flush, so not all changes are yet
-             * written. However, Synchronization-s do propagate exceptions, so they can be safely used. 
-             */
             session.getActionQueue().registerProcess(auditProcess);
-            session.getTransaction().registerSynchronization(auditProcess);
 
             session.getActionQueue().registerProcess(new AfterTransactionCompletionProcess() {
                 public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {



More information about the hibernate-commits mailing list