HHH-5384 - HEM should not register its own Synchronization
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19962 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
207a95a49a
commit
1dd65401f3
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,6 +41,8 @@ import org.hibernate.Interceptor;
|
|||
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 @@ public class JDBCContext implements Serializable, ConnectionManager.Callback {
|
|||
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 @@ public class JDBCContext implements Serializable, ConnectionManager.Callback {
|
|||
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 @@ public class JDBCContext implements Serializable, ConnectionManager.Callback {
|
|||
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;
|
||||
|
|
|
@ -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.slf4j.LoggerFactory;
|
|||
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 @@ import org.hibernate.jdbc.JDBCContext;
|
|||
* @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 @@ public class JDBCTransaction implements Transaction {
|
|||
private boolean rolledBack;
|
||||
private boolean committed;
|
||||
private boolean commitFailed;
|
||||
private List synchronizations;
|
||||
private boolean callback;
|
||||
private int timeout = -1;
|
||||
|
||||
|
@ -137,7 +133,7 @@ public class JDBCTransaction implements Transaction {
|
|||
transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
|
||||
}
|
||||
|
||||
notifyLocalSynchsBeforeTransactionCompletion();
|
||||
notifySynchronizationsBeforeTransactionCompletion();
|
||||
if ( callback ) {
|
||||
jdbcContext.beforeTransactionCompletion( this );
|
||||
}
|
||||
|
@ -149,7 +145,7 @@ public class JDBCTransaction implements Transaction {
|
|||
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 @@ public class JDBCTransaction implements Transaction {
|
|||
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 @@ public class JDBCTransaction implements Transaction {
|
|||
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 @@ public class JDBCTransaction implements Transaction {
|
|||
/**
|
||||
* {@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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -101,6 +101,10 @@ import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
|
|||
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 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
//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
|
||||
}
|
||||
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;
|
||||
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" );
|
||||
}
|
||||
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 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
}
|
||||
}
|
||||
);
|
||||
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 );
|
||||
|
|
|
@ -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.envers.tools.Pair;
|
|||
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 @@ public class AuditProcess implements BeforeTransactionCompletionProcess, Synchro
|
|||
session.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronization methods
|
||||
|
||||
public void beforeCompletion() {
|
||||
doBeforeTransactionCompletion(session);
|
||||
}
|
||||
|
||||
public void afterCompletion(int status) { }
|
||||
}
|
||||
|
|
|
@ -55,18 +55,7 @@ public class AuditProcessManager {
|
|||
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) {
|
||||
|
|
Loading…
Reference in New Issue