Java tutorial
/* * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.orm.hibernate3; import java.util.ArrayList; import java.util.List; import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.Synchronization; import javax.transaction.SystemException; import javax.transaction.TransactionManager; import javax.transaction.UserTransaction; import org.hibernate.FlushMode; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.SessionFactory; import org.hibernate.classic.Session; import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionImplementor; import org.junit.After; import org.junit.Test; import org.mockito.InOrder; import org.springframework.dao.DataAccessException; import org.springframework.tests.transaction.MockJtaTransaction; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.UnexpectedRollbackException; import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionTemplate; import static org.junit.Assert.*; import static org.mockito.BDDMockito.*; /** * @author Juergen Hoeller * @author Phillip Webb * @since 05.03.2005 */ public class HibernateJtaTransactionTests { @After public void tearDown() { assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); } @Test public void testJtaTransactionCommit() throws Exception { doTestJtaTransactionCommit(Status.STATUS_NO_TRANSACTION, false); } @Test public void testJtaTransactionCommitWithReadOnly() throws Exception { doTestJtaTransactionCommit(Status.STATUS_NO_TRANSACTION, true); } @Test public void testJtaTransactionCommitWithExisting() throws Exception { doTestJtaTransactionCommit(Status.STATUS_ACTIVE, false); } @Test public void testJtaTransactionCommitWithExistingAndReadOnly() throws Exception { doTestJtaTransactionCommit(Status.STATUS_ACTIVE, true); } @SuppressWarnings({ "rawtypes", "unchecked" }) private void doTestJtaTransactionCommit(int status, final boolean readOnly) throws Exception { UserTransaction ut = mock(UserTransaction.class); final SessionFactory sf = mock(SessionFactory.class); final Session session = mock(Session.class); Query query = mock(Query.class); if (status == Status.STATUS_NO_TRANSACTION) { given(ut.getStatus()).willReturn(status, Status.STATUS_ACTIVE); } else { given(ut.getStatus()).willReturn(status); } final List list = new ArrayList(); list.add("test"); given(sf.openSession()).willReturn(session); given(session.getSessionFactory()).willReturn(sf); given(session.isOpen()).willReturn(true); given(session.createQuery("some query string")).willReturn(query); given(query.list()).willReturn(list); given(session.getFlushMode()).willReturn(FlushMode.AUTO); JtaTransactionManager ptm = new JtaTransactionManager(ut); TransactionTemplate tt = new TransactionTemplate(ptm); tt.setReadOnly(readOnly); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); Object result = tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { try { assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); ht = new HibernateTemplate(sf); List htl = ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); return sess.createQuery("some query string").list(); } }); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); return htl; } catch (Error err) { err.printStackTrace(); throw err; } } }); assertTrue("Correct result list", result == list); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); if (status == Status.STATUS_NO_TRANSACTION) { InOrder ordered = inOrder(ut); ordered.verify(ut).begin(); ordered.verify(ut).commit(); } if (readOnly) { verify(session).setFlushMode(FlushMode.MANUAL); } else { verify(session).flush(); } verify(session).close(); } @Test public void testJtaTransactionCommitWithJtaTm() throws Exception { doTestJtaTransactionCommitWithJtaTm(Status.STATUS_NO_TRANSACTION); } @Test public void testJtaTransactionCommitWithJtaTmAndExisting() throws Exception { doTestJtaTransactionCommitWithJtaTm(Status.STATUS_ACTIVE); } @SuppressWarnings({ "rawtypes", "unchecked" }) private void doTestJtaTransactionCommitWithJtaTm(int status) throws Exception { UserTransaction ut = mock(UserTransaction.class); if (status == Status.STATUS_NO_TRANSACTION) { given(ut.getStatus()).willReturn(status, status, Status.STATUS_ACTIVE); } else { given(ut.getStatus()).willReturn(status); } TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getTransaction()).willReturn(transaction); final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final Session session = mock(Session.class); given(sf.getTransactionManager()).willReturn(tm); given(sf.openSession()).willReturn(session); given(session.isOpen()).willReturn(true); given(session.getFlushMode()).willReturn(FlushMode.AUTO); JtaTransactionManager ptm = new JtaTransactionManager(ut); TransactionTemplate tt = new TransactionTemplate(ptm); final List l = new ArrayList(); l.add("test"); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); Object result = tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { try { assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); List htl = ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return l; } }); ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); htl = ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return l; } }); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); return htl; } catch (Error err) { err.printStackTrace(); throw err; } } }); assertTrue("Correct result list", result == l); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); if (status == Status.STATUS_NO_TRANSACTION) { InOrder ordered = inOrder(ut); ordered.verify(ut).begin(); ordered.verify(ut).commit(); } verify(session).flush(); verify(session).close(); } @Test @SuppressWarnings({ "rawtypes", "unchecked" }) public void testJtaTransactionWithFlushFailure() throws Exception { UserTransaction ut = mock(UserTransaction.class); given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE); final SessionFactory sf = mock(SessionFactory.class); final Session session = mock(Session.class); given(sf.openSession()).willReturn(session); given(session.getSessionFactory()).willReturn(sf); given(session.isOpen()).willReturn(true); given(session.getFlushMode()).willReturn(FlushMode.AUTO); JtaTransactionManager ptm = new JtaTransactionManager(ut); TransactionTemplate tt = new TransactionTemplate(ptm); final List l = new ArrayList(); l.add("test"); final HibernateException flushEx = new HibernateException("flush failure"); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); willThrow(flushEx).given(session).flush(); try { tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { try { assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); List htl = ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return l; } }); ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); htl = ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return l; } }); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); return htl; } catch (Error err) { err.printStackTrace(); throw err; } } }); } catch (DataAccessException ex) { // expected assertTrue(flushEx == ex.getCause()); } assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); verify(ut).begin(); verify(ut).rollback(); verify(session).close(); } @Test public void testJtaTransactionRollback() throws Exception { doTestJtaTransactionRollback(false); } @Test public void testJtaTransactionRollbackWithFlush() throws Exception { doTestJtaTransactionRollback(true); } @SuppressWarnings({ "rawtypes", "unchecked" }) private void doTestJtaTransactionRollback(final boolean flush) throws Exception { UserTransaction ut = mock(UserTransaction.class); given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE); final SessionFactory sf = mock(SessionFactory.class); final Session session = mock(Session.class); given(sf.openSession()).willReturn(session); given(session.getSessionFactory()).willReturn(sf); JtaTransactionManager ptm = new JtaTransactionManager(ut); TransactionTemplate tt = new TransactionTemplate(ptm); final List l = new ArrayList(); l.add("test"); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); Object result = tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { try { assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); HibernateTemplate ht = new HibernateTemplate(sf); List htl = ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session session) { return l; } }); if (flush) { status.flush(); } status.setRollbackOnly(); return htl; } catch (Error err) { err.printStackTrace(); throw err; } } }); assertTrue("Correct result list", result == l); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); InOrder ordered = inOrder(ut); ordered.verify(ut).begin(); ordered.verify(ut).rollback(); if (flush) { verify(session).flush(); } verify(session).close(); } @Test public void testJtaTransactionCommitWithPreBound() throws Exception { doTestJtaTransactionCommitWithPreBound(false, false, false); } @Test public void testJtaTransactionCommitWithPreBoundAndReadOnly() throws Exception { doTestJtaTransactionCommitWithPreBound(false, false, true); } @Test public void testJtaTransactionCommitWithPreBoundAndFlushModeNever() throws Exception { doTestJtaTransactionCommitWithPreBound(false, true, false); } @Test public void testJtaTransactionCommitWithPreBoundAndFlushModeNeverAndReadOnly() throws Exception { doTestJtaTransactionCommitWithPreBound(false, true, true); } @Test public void testJtaTransactionCommitWithJtaTmAndPreBound() throws Exception { doTestJtaTransactionCommitWithPreBound(true, false, false); } @Test public void testJtaTransactionCommitWithJtaTmAndPreBoundAndReadOnly() throws Exception { doTestJtaTransactionCommitWithPreBound(true, false, true); } @Test public void testJtaTransactionCommitWithJtaTmAndPreBoundAndFlushModeNever() throws Exception { doTestJtaTransactionCommitWithPreBound(true, true, false); } @Test public void testJtaTransactionCommitWithJtaTmAndPreBoundAndFlushModeNeverAndReadOnly() throws Exception { doTestJtaTransactionCommitWithPreBound(true, true, true); } @SuppressWarnings({ "rawtypes", "unchecked" }) protected void doTestJtaTransactionCommitWithPreBound(boolean jtaTm, final boolean flushNever, final boolean readOnly) throws Exception { UserTransaction ut = mock(UserTransaction.class); given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE); TransactionManager tm = mock(TransactionManager.class); if (jtaTm) { MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getTransaction()).willReturn(transaction); } final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final ExtendedSession session = mock(ExtendedSession.class); given(sf.getTransactionManager()).willReturn(jtaTm ? tm : null); given(session.isOpen()).willReturn(true); given(session.getFlushMode()).willReturn(flushNever ? FlushMode.MANUAL : FlushMode.AUTO); TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); try { JtaTransactionManager ptm = new JtaTransactionManager(ut); TransactionTemplate tt = new TransactionTemplate(ptm); tt.setReadOnly(readOnly); final List l = new ArrayList(); l.add("test"); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); Object result = tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { try { assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); List htl = null; for (int i = 0; i < 5; i++) { htl = ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return l; } }); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); } return htl; } catch (Error err) { err.printStackTrace(); throw err; } } }); assertTrue("Correct result list", result == l); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); } finally { TransactionSynchronizationManager.unbindResource(sf); } verify(ut).begin(); verify(ut).commit(); if (flushNever) { if (!readOnly) { InOrder ordered = inOrder(session); ordered.verify(session).setFlushMode(FlushMode.AUTO); ordered.verify(session).setFlushMode(FlushMode.MANUAL); } } if (!flushNever && !readOnly) { verify(session).flush(); } verify(session).afterTransactionCompletion(true, null); verify(session).disconnect(); } @Test @SuppressWarnings({ "rawtypes", "unchecked" }) public void testJtaTransactionRollbackWithPreBound() throws Exception { UserTransaction ut = mock(UserTransaction.class); given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE, Status.STATUS_MARKED_ROLLBACK, Status.STATUS_MARKED_ROLLBACK); RollbackException rex = new RollbackException(); willThrow(rex).given(ut).commit(); final SessionFactory sf = mock(SessionFactory.class); final Session session = mock(Session.class); given(session.getSessionFactory()).willReturn(sf); given(session.isOpen()).willReturn(true); given(session.getFlushMode()).willReturn(FlushMode.AUTO); TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); try { JtaTransactionManager ptm = new JtaTransactionManager(ut); final TransactionTemplate tt = new TransactionTemplate(ptm); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); tt.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { tt.execute(new TransactionCallbackWithoutResult() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { status.setRollbackOnly(); try { assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); for (int i = 0; i < 5; i++) { ht.execute(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); } } catch (Error err) { err.printStackTrace(); throw err; } } }); } }); fail("Should have thrown UnexpectedRollbackException"); } catch (UnexpectedRollbackException ex) { // expected assertEquals(rex, ex.getCause()); } finally { TransactionSynchronizationManager.unbindResource(sf); } verify(ut).begin(); verify(ut).setRollbackOnly(); verify(session).flush(); verify(session).disconnect(); verify(session).clear(); } @Test public void testJtaTransactionCommitWithRequiresNew() throws Exception { doTestJtaTransactionWithRequiresNew(false); } @Test public void testJtaTransactionRollbackWithRequiresNew() throws Exception { doTestJtaTransactionWithRequiresNew(true); } @SuppressWarnings({ "rawtypes", "unchecked" }) protected void doTestJtaTransactionWithRequiresNew(final boolean rollback) throws Exception { UserTransaction ut = mock(UserTransaction.class); TransactionManager tm = mock(TransactionManager.class); javax.transaction.Transaction tx1 = mock(javax.transaction.Transaction.class); final SessionFactory sf = mock(SessionFactory.class); final Session session1 = mock(Session.class); final Session session2 = mock(Session.class); given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE); given(tm.suspend()).willReturn(tx1); given(sf.openSession()).willReturn(session1, session2); given(session1.getSessionFactory()).willReturn(sf); given(session2.getSessionFactory()).willReturn(sf); given(session1.isOpen()).willReturn(true); given(session2.isOpen()).willReturn(true); given(session2.getFlushMode()).willReturn(FlushMode.AUTO); if (!rollback) { given(session1.getFlushMode()).willReturn(FlushMode.AUTO); } JtaTransactionManager ptm = new JtaTransactionManager(); ptm.setUserTransaction(ut); ptm.setTransactionManager(tm); final TransactionTemplate tt = new TransactionTemplate(ptm); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); try { tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { org.hibernate.Session outerSession = SessionFactoryUtils.getSession(sf, false); assertSame(session1, outerSession); SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); assertTrue("Has thread session", holder != null); try { tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { org.hibernate.Session innerSession = SessionFactoryUtils.getSession(sf, false); assertSame(session2, innerSession); HibernateTemplate ht = new HibernateTemplate(sf); ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); return ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session innerSession) { if (rollback) { throw new HibernateException(""); } return null; } }); } }); return null; } finally { assertTrue("Same thread session as before", outerSession == SessionFactoryUtils.getSession(sf, false)); } } }); if (rollback) { fail("Should have thrown DataAccessException"); } } catch (DataAccessException ex) { if (!rollback) { throw ex; } } finally { assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); } verify(ut, times(2)).begin(); verify(tm).resume(tx1); if (rollback) { verify(ut, times(2)).rollback(); } else { verify(ut, times(2)).commit(); } verify(session1).disconnect(); verify(session1).close(); if (!rollback) { verify(session1).flush(); verify(session2, atLeastOnce()).flush(); } verify(session2).close(); } @Test public void testJtaTransactionWithRequiresNewAndSuspendException() throws Exception { doTestJtaTransactionWithRequiresNewAndException(true); } @Test public void testJtaTransactionWithRequiresNewAndBeginException() throws Exception { doTestJtaTransactionWithRequiresNewAndException(false); } @SuppressWarnings({ "rawtypes", "unchecked" }) protected void doTestJtaTransactionWithRequiresNewAndException(boolean suspendException) throws Exception { UserTransaction ut = mock(UserTransaction.class); TransactionManager tm = mock(TransactionManager.class); javax.transaction.Transaction tx = mock(javax.transaction.Transaction.class); final SessionFactory sf = mock(SessionFactory.class); final Session session1 = mock(Session.class); given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE); if (suspendException) { given(tm.suspend()).willThrow(new SystemException()); } else { given(tm.suspend()).willReturn(tx); willDoNothing().willThrow(new SystemException()).given(ut).begin(); } given(sf.openSession()).willReturn(session1); given(session1.getSessionFactory()).willReturn(sf); JtaTransactionManager ptm = new JtaTransactionManager(); ptm.setUserTransaction(ut); ptm.setTransactionManager(tm); final TransactionTemplate tt = new TransactionTemplate(ptm); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); try { tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { org.hibernate.Session outerSession = SessionFactoryUtils.getSession(sf, false); assertSame(session1, outerSession); SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); assertTrue("Has thread session", holder != null); tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { return null; } }); return null; } }); fail("Should have thrown TransactionException"); } catch (TransactionException ex) { // expected } finally { assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); } verify(ut, atLeastOnce()).begin(); if (!suspendException) { verify(tm).resume(tx); } verify(ut).rollback(); verify(session1).disconnect(); verify(session1).close(); } @Test public void testJtaTransactionCommitWithRequiresNewAndJtaTm() throws Exception { doTestJtaTransactionWithRequiresNewAndJtaTm(false); } @Test public void testJtaTransactionRollbackWithRequiresNewAndJtaTm() throws Exception { doTestJtaTransactionWithRequiresNewAndJtaTm(true); } @SuppressWarnings({ "rawtypes", "unchecked" }) protected void doTestJtaTransactionWithRequiresNewAndJtaTm(final boolean rollback) throws Exception { UserTransaction ut = mock(UserTransaction.class); TransactionManager tm = mock(TransactionManager.class); javax.transaction.Transaction tx1 = mock(javax.transaction.Transaction.class); final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final Session session1 = mock(Session.class); final Session session2 = mock(Session.class); MockJtaTransaction transaction1 = new MockJtaTransaction(); MockJtaTransaction transaction2 = new MockJtaTransaction(); given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE); given(tm.getTransaction()).willReturn(transaction1); given(tm.suspend()).willReturn(tx1); given(tm.getTransaction()).willReturn(transaction2); given(sf.getTransactionManager()).willReturn(tm); given(sf.openSession()).willReturn(session1, session2); given(session1.isOpen()).willReturn(true); given(session2.isOpen()).willReturn(true); given(session1.getFlushMode()).willReturn(FlushMode.AUTO); given(session2.getFlushMode()).willReturn(FlushMode.AUTO); JtaTransactionManager ptm = new JtaTransactionManager(); ptm.setUserTransaction(ut); ptm.setTransactionManager(tm); final TransactionTemplate tt = new TransactionTemplate(ptm); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); try { tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { org.hibernate.Session outerSession = SessionFactoryUtils.getSession(sf, false); assertSame(session1, outerSession); SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); assertTrue("Has thread session", holder != null); try { tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { org.hibernate.Session innerSession = SessionFactoryUtils.getSession(sf, false); assertSame(session2, innerSession); HibernateTemplate ht = new HibernateTemplate(sf); ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); return ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session innerSession) { if (rollback) { throw new HibernateException(""); } return null; } }); } }); return null; } finally { assertTrue("Same thread session as before", outerSession == SessionFactoryUtils.getSession(sf, false)); } } }); if (rollback) { fail("Should have thrown DataAccessException"); } } catch (DataAccessException ex) { if (!rollback) { throw ex; } } finally { assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); } verify(ut, times(2)).begin(); verify(tm).resume(tx1); if (rollback) { verify(ut, times(2)).rollback(); } else { verify(ut, times(2)).commit(); verify(session1).flush(); verify(session2, times(2)).flush(); } verify(session1).disconnect(); verify(session1).close(); verify(session2).close(); } @Test @SuppressWarnings({ "rawtypes", "unchecked" }) public void testTransactionWithPropagationSupports() throws Exception { UserTransaction ut = mock(UserTransaction.class); given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE); final SessionFactory sf = mock(SessionFactory.class); final Session session = mock(Session.class); given(sf.openSession()).willReturn(session); given(session.getSessionFactory()).willReturn(sf); given(session.getFlushMode()).willReturn(FlushMode.MANUAL); JtaTransactionManager tm = new JtaTransactionManager(ut); TransactionTemplate tt = new TransactionTemplate(tm); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("Is not new transaction", !status.isNewTransaction()); assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); HibernateTemplate ht = new HibernateTemplate(sf); ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); ht.execute(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session session) { return null; } }); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); return null; } }); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); InOrder ordered = inOrder(session); ordered.verify(session).setFlushMode(FlushMode.AUTO); ordered.verify(session).flush(); ordered.verify(session).setFlushMode(FlushMode.MANUAL); ordered.verify(session).close(); } @Test @SuppressWarnings({ "rawtypes", "unchecked" }) public void testTransactionWithPropagationSupportsAndInnerTransaction() throws Exception { UserTransaction ut = mock(UserTransaction.class); given(ut.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE); final SessionFactory sf = mock(SessionFactory.class); final Session session = mock(Session.class); given(sf.openSession()).willReturn(session); given(session.getSessionFactory()).willReturn(sf); given(session.isOpen()).willReturn(true); given(session.getFlushMode()).willReturn(FlushMode.AUTO); JtaTransactionManager tm = new JtaTransactionManager(ut); TransactionTemplate tt = new TransactionTemplate(tm); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); final TransactionTemplate tt2 = new TransactionTemplate(tm); tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); tt.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("Is not new transaction", !status.isNewTransaction()); assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); HibernateTemplate ht = new HibernateTemplate(sf); ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); ht.execute(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session session) { return null; } }); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); tt2.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { HibernateTemplate ht = new HibernateTemplate(sf); ht.setFlushMode(HibernateTemplate.FLUSH_EAGER); return ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session session) { assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); // assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); return null; } }); } }); assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); return null; } }); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); verify(session, times(3)).flush(); verify(session).close(); } @Test @SuppressWarnings("rawtypes") public void testJtaSessionSynchronization() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getTransaction()).willReturn(transaction); final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final Session session = mock(Session.class); given(sf.openSession()).willReturn(session); given(sf.getTransactionManager()).willReturn(tm); given(session.isOpen()).willReturn(true); given(session.getFlushMode()).willReturn(FlushMode.AUTO); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); for (int i = 0; i < 5; i++) { ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); } Synchronization synchronization = transaction.getSynchronization(); assertTrue("JTA synchronization registered", synchronization != null); synchronization.beforeCompletion(); synchronization.afterCompletion(Status.STATUS_COMMITTED); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); verify(session).flush(); verify(session).close(); } @Test @SuppressWarnings("rawtypes") public void testJtaSessionSynchronizationWithRollback() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getTransaction()).willReturn(transaction); final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final Session session = mock(Session.class); given(sf.openSession()).willReturn(session); given(sf.getTransactionManager()).willReturn(tm); given(session.isOpen()).willReturn(true); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); for (int i = 0; i < 5; i++) { ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); } Synchronization synchronization = transaction.getSynchronization(); assertTrue("JTA synchronization registered", synchronization != null); synchronization.afterCompletion(Status.STATUS_ROLLEDBACK); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); verify(session).close(); } @Test @SuppressWarnings("rawtypes") public void testJtaSessionSynchronizationWithRollbackByOtherThread() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getTransaction()).willReturn(transaction); given(tm.getStatus()).willReturn(Status.STATUS_NO_TRANSACTION); final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final Session session = mock(Session.class); given(sf.openSession()).willReturn(session); given(sf.getTransactionManager()).willReturn(tm); given(session.isOpen()).willReturn(true); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); final HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); for (int i = 0; i < 5; i++) { ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); } final Synchronization synchronization = transaction.getSynchronization(); assertTrue("JTA synchronization registered", synchronization != null); Thread thread = new Thread() { @Override public void run() { synchronization.afterCompletion(Status.STATUS_ROLLEDBACK); } }; thread.start(); thread.join(); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); TransactionTemplate tt = new TransactionTemplate(new JtaTransactionManager(tm)); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); tt.setReadOnly(true); tt.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); for (int i = 0; i < 5; i++) { ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); } } }); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); verify(session).setFlushMode(FlushMode.MANUAL); verify(session, times(2)).close(); } @Test @SuppressWarnings("rawtypes") public void testJtaSessionSynchronizationWithFlushFailure() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getTransaction()).willReturn(transaction); final HibernateException flushEx = new HibernateException("flush failure"); final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final Session session = mock(Session.class); given(sf.openSession()).willReturn(session); given(sf.getTransactionManager()).willReturn(tm); given(session.isOpen()).willReturn(true); given(session.getFlushMode()).willReturn(FlushMode.AUTO); willThrow(flushEx).given(session).flush(); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); for (int i = 0; i < 5; i++) { ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); } Synchronization synchronization = transaction.getSynchronization(); assertTrue("JTA synchronization registered", synchronization != null); try { synchronization.beforeCompletion(); fail("Should have thrown HibernateSystemException"); } catch (HibernateSystemException ex) { assertSame(flushEx, ex.getCause()); } synchronization.afterCompletion(Status.STATUS_ROLLEDBACK); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); verify(tm).setRollbackOnly(); verify(session).close(); } @Test @SuppressWarnings("rawtypes") public void testJtaSessionSynchronizationWithSuspendedTransaction() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction1 = new MockJtaTransaction(); MockJtaTransaction transaction2 = new MockJtaTransaction(); given(tm.getTransaction()).willReturn(transaction1, transaction1, transaction2, transaction2, transaction2); final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final Session session1 = mock(Session.class); final Session session2 = mock(Session.class); given(sf.openSession()).willReturn(session1, session2); given(sf.getTransactionManager()).willReturn(tm); given(session1.getFlushMode()).willReturn(FlushMode.AUTO); given(session2.getFlushMode()).willReturn(FlushMode.AUTO); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session1, sess); return null; } }); ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session2, sess); return null; } }); Synchronization synchronization2 = transaction2.getSynchronization(); assertTrue("JTA synchronization registered", synchronization2 != null); synchronization2.beforeCompletion(); synchronization2.afterCompletion(Status.STATUS_COMMITTED); Synchronization synchronization1 = transaction1.getSynchronization(); assertTrue("JTA synchronization registered", synchronization1 != null); synchronization1.beforeCompletion(); synchronization1.afterCompletion(Status.STATUS_COMMITTED); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); verify(session1).flush(); verify(session2).flush(); verify(session1).close(); verify(session2).close(); } @Test @SuppressWarnings("rawtypes") public void testJtaSessionSynchronizationWithNonSessionFactoryImplementor() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getTransaction()).willReturn(transaction); final SessionFactory sf = mock(SessionFactory.class); final Session session = mock(Session.class); final SessionFactoryImplementor sfi = mock(SessionFactoryImplementor.class); given(sf.openSession()).willReturn(session); given(session.getSessionFactory()).willReturn(sfi); given(sfi.getTransactionManager()).willReturn(tm); given(session.isOpen()).willReturn(true); given(session.getFlushMode()).willReturn(FlushMode.AUTO); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); for (int i = 0; i < 5; i++) { ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); } Synchronization synchronization = transaction.getSynchronization(); assertTrue("JTA Synchronization registered", synchronization != null); synchronization.beforeCompletion(); synchronization.afterCompletion(Status.STATUS_COMMITTED); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); verify(session).flush(); verify(session).close(); } @Test @SuppressWarnings("rawtypes") public void testJtaSessionSynchronizationWithSpringTransactionLaterOn() throws Exception { UserTransaction ut = mock(UserTransaction.class); TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(ut.getStatus()).willReturn(Status.STATUS_ACTIVE); given(tm.getTransaction()).willReturn(transaction); final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final Session session = mock(Session.class); given(sf.openSession()).willReturn(session); given(sf.getTransactionManager()).willReturn(tm); given(session.isOpen()).willReturn(true); given(session.getFlushMode()).willReturn(FlushMode.AUTO); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); final HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); for (int i = 0; i < 2; i++) { ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); } TransactionTemplate tt = new TransactionTemplate(new JtaTransactionManager(ut)); tt.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { for (int i = 2; i < 5; i++) { ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); } } }); Synchronization synchronization = transaction.getSynchronization(); assertTrue("JTA synchronization registered", synchronization != null); synchronization.beforeCompletion(); synchronization.afterCompletion(Status.STATUS_COMMITTED); assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); verify(session).flush(); verify(session).close(); } @Test public void testJtaSessionSynchronizationWithPreBound() throws Exception { doTestJtaSessionSynchronizationWithPreBound(false); } @Test public void testJtaJtaSessionSynchronizationWithPreBoundAndFlushNever() throws Exception { doTestJtaSessionSynchronizationWithPreBound(true); } @SuppressWarnings("rawtypes") private void doTestJtaSessionSynchronizationWithPreBound(boolean flushNever) throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); given(tm.getTransaction()).willReturn(transaction); final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final Session session = mock(Session.class); given(sf.getTransactionManager()).willReturn(tm); given(session.isOpen()).willReturn(true); if (flushNever) { given(session.getFlushMode()).willReturn(FlushMode.MANUAL, FlushMode.AUTO, FlushMode.MANUAL); } else { given(session.getFlushMode()).willReturn(FlushMode.AUTO); } assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session)); try { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); for (int i = 0; i < 5; i++) { ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); } Synchronization synchronization = transaction.getSynchronization(); assertTrue("JTA synchronization registered", synchronization != null); synchronization.beforeCompletion(); synchronization.afterCompletion(Status.STATUS_COMMITTED); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); } finally { TransactionSynchronizationManager.unbindResource(sf); } assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); InOrder ordered = inOrder(session); if (flushNever) { ordered.verify(session).setFlushMode(FlushMode.AUTO); ordered.verify(session).setFlushMode(FlushMode.MANUAL); } else { ordered.verify(session).flush(); } ordered.verify(session).disconnect(); } @Test @SuppressWarnings("rawtypes") public void testJtaSessionSynchronizationWithRemoteTransaction() throws Exception { TransactionManager tm = mock(TransactionManager.class); MockJtaTransaction transaction = new MockJtaTransaction(); final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class); final Session session = mock(Session.class); given(tm.getTransaction()).willReturn(transaction); given(sf.openSession()).willReturn(session); given(sf.getTransactionManager()).willReturn(tm); given(session.isOpen()).willReturn(true); given(session.getFlushMode()).willReturn(FlushMode.AUTO); for (int j = 0; j < 2; j++) { if (j == 0) { assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf)); } else { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); } HibernateTemplate ht = new HibernateTemplate(sf); ht.setExposeNativeSession(true); for (int i = 0; i < 5; i++) { ht.executeFind(new HibernateCallback() { @Override public Object doInHibernate(org.hibernate.Session sess) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); assertEquals(session, sess); return null; } }); } final Synchronization synchronization = transaction.getSynchronization(); assertTrue("JTA synchronization registered", synchronization != null); // Call synchronization in a new thread, to simulate a // synchronization // triggered by a new remote call from a remote transaction // coordinator. Thread synch = new Thread() { @Override public void run() { synchronization.beforeCompletion(); synchronization.afterCompletion(Status.STATUS_COMMITTED); } }; synch.start(); synch.join(); assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf)); SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf); assertTrue("Thread session holder empty", sessionHolder.isEmpty()); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); } verify(session, times(2)).flush(); verify(session, times(2)).close(); TransactionSynchronizationManager.unbindResource(sf); } /** * Interface that combines Hibernate's Session and SessionImplementor * interface. Necessary for creating a mock that implements both interfaces. * Note: Hibernate 3.1's SessionImplementor interface does not extend * Session anymore. */ public static interface ExtendedSession extends Session, SessionImplementor { } }