Author: steve.ebersole(a)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) {