/* * Copyright 2002-2007 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.jdo; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; import java.sql.Savepoint; import java.util.ArrayList; import java.util.List; import javax.jdo.JDOFatalDataStoreException; import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManagerFactory; import javax.jdo.Query; import javax.jdo.Transaction; import javax.sql.DataSource; import javax.transaction.Status; import javax.transaction.TransactionManager; import javax.transaction.UserTransaction; import junit.framework.TestCase; import org.easymock.MockControl; import org.springframework.beans.TestBean; import org.springframework.jdbc.datasource.ConnectionHandle; import org.springframework.jdbc.datasource.ConnectionHolder; import org.springframework.jdbc.datasource.SimpleConnectionHandle; import org.springframework.transaction.InvalidIsolationLevelException; import org.springframework.transaction.MockJtaTransaction; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; 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; /** * @author Juergen Hoeller */ public class JdoTransactionManagerTests extends TestCase { private MockControl pmfControl, pmControl, txControl; private PersistenceManagerFactory pmf; private PersistenceManager pm; private Transaction tx; protected void setUp() { pmfControl = MockControl.createControl(PersistenceManagerFactory.class); pmf = (PersistenceManagerFactory) pmfControl.getMock(); pmControl = MockControl.createControl(PersistenceManager.class); pm = (PersistenceManager) pmControl.getMock(); txControl = MockControl.createControl(Transaction.class); tx = (Transaction) txControl.getMock(); pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 1); } protected void tearDown() { try { pmfControl.verify(); pmControl.verify(); } catch (IllegalStateException ex) { // ignore: test method didn't call replay } assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly()); assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); } public void testTransactionCommit() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 3); pm.flush(); pmControl.setVoidCallable(2); pm.close(); pmControl.setVoidCallable(1); tx.begin(); txControl.setVoidCallable(1); tx.getRollbackOnly(); txControl.setReturnValue(false, 1); tx.commit(); txControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); txControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); TransactionTemplate tt = new TransactionTemplate(tm); final List l = new ArrayList(); l.add("test"); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); TransactionAwarePersistenceManagerFactoryProxy proxyFactory = new TransactionAwarePersistenceManagerFactoryProxy(); proxyFactory.setTargetPersistenceManagerFactory(pmf); PersistenceManagerFactory proxy = (PersistenceManagerFactory) proxyFactory.getObject(); assertEquals(pm.toString(), proxy.getPersistenceManager().toString()); proxy.getPersistenceManager().flush(); proxy.getPersistenceManager().close(); JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { pm2.flush(); return l; } }); } }); assertTrue("Correct result list", result == l); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); } public void testTransactionRollback() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 2); pm.close(); pmControl.setVoidCallable(1); tx.begin(); txControl.setVoidCallable(1); tx.isActive(); txControl.setReturnValue(true, 1); tx.rollback(); txControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); txControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); TransactionTemplate tt = new TransactionTemplate(tm); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); try { tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm) { throw new RuntimeException("application exception"); } }); } }); fail("Should have thrown RuntimeException"); } catch (RuntimeException ex) { // expected } assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); } public void testTransactionRollbackWithAlreadyRolledBack() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 2); pm.close(); pmControl.setVoidCallable(1); tx.begin(); txControl.setVoidCallable(1); tx.isActive(); txControl.setReturnValue(false, 1); pmfControl.replay(); pmControl.replay(); txControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); TransactionTemplate tt = new TransactionTemplate(tm); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); try { tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm) { throw new RuntimeException("application exception"); } }); } }); fail("Should have thrown RuntimeException"); } catch (RuntimeException ex) { // expected } assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); } public void testTransactionRollbackOnly() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 2); pm.flush(); pmControl.setVoidCallable(1); pm.close(); pmControl.setVoidCallable(1); tx.begin(); txControl.setVoidCallable(1); tx.isActive(); txControl.setReturnValue(true, 1); tx.rollback(); txControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); txControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); TransactionTemplate tt = new TransactionTemplate(tm); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); JdoTemplate jt = new JdoTemplate(pmf); jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { pm2.flush(); return null; } }); status.setRollbackOnly(); return null; } }); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); } public void testParticipatingTransactionWithCommit() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 3); pm.flush(); pmControl.setVoidCallable(1); pm.close(); pmControl.setVoidCallable(1); tx.begin(); txControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); txControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); final TransactionTemplate tt = new TransactionTemplate(tm); final List l = new ArrayList(); l.add("test"); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { txControl.reset(); tx.isActive(); txControl.setReturnValue(true, 1); tx.getRollbackOnly(); txControl.setReturnValue(false, 1); tx.commit(); txControl.setVoidCallable(1); txControl.replay(); return tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { pm2.flush(); return l; } }); } }); } }); assertTrue("Correct result list", result == l); } public void testParticipatingTransactionWithRollback() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 3); pm.close(); pmControl.setVoidCallable(1); tx.isActive(); txControl.setReturnValue(false, 1); tx.begin(); txControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); txControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); final TransactionTemplate tt = new TransactionTemplate(tm); try { tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { txControl.reset(); tx.isActive(); txControl.setReturnValue(true, 3); tx.setRollbackOnly(); txControl.setVoidCallable(1); tx.rollback(); txControl.setVoidCallable(1); txControl.replay(); return tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm) { throw new RuntimeException("application exception"); } }); } }); } }); fail("Should have thrown RuntimeException"); } catch (RuntimeException ex) { // expected } } public void testParticipatingTransactionWithRollbackOnly() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 5); pm.flush(); pmControl.setVoidCallable(1); pm.close(); pmControl.setVoidCallable(1); tx.begin(); txControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); txControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); final TransactionTemplate tt = new TransactionTemplate(tm); final List l = new ArrayList(); l.add("test"); try { tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { txControl.reset(); tx.isActive(); txControl.setReturnValue(true, 1); tx.setRollbackOnly(); txControl.setVoidCallable(1); tx.getRollbackOnly(); txControl.setReturnValue(true, 1); tx.commit(); txControl.setThrowable(new JDOFatalDataStoreException(), 1); tx.isActive(); txControl.setReturnValue(false, 1); txControl.replay(); return tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { JdoTemplate jt = new JdoTemplate(pmf); jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { pm2.flush(); return l; } }); status.setRollbackOnly(); return null; } }); } }); fail("Should have thrown JdoResourceFailureException"); } catch (JdoResourceFailureException ex) { // expected } } public void testParticipatingTransactionWithWithRequiresNew() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 2); pm.currentTransaction(); pmControl.setReturnValue(tx, 6); tx.begin(); txControl.setVoidCallable(1); pm.flush(); pmControl.setVoidCallable(1); pm.close(); pmControl.setVoidCallable(2); pmfControl.replay(); pmControl.replay(); txControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); final TransactionTemplate tt = new TransactionTemplate(tm); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); final List l = new ArrayList(); l.add("test"); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { txControl.verify(); txControl.reset(); tx.isActive(); txControl.setReturnValue(true, 1); tx.begin(); txControl.setVoidCallable(1); tx.getRollbackOnly(); txControl.setReturnValue(false, 2); tx.commit(); txControl.setVoidCallable(2); txControl.replay(); return tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { pm2.flush(); return l; } }); } }); } }); assertTrue("Correct result list", result == l); } public void testParticipatingTransactionWithWithRequiresNewAndPrebound() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 3); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 6); tx.begin(); txControl.setVoidCallable(1); pm.flush(); pmControl.setVoidCallable(1); pm.close(); pmControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); txControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); final TransactionTemplate tt = new TransactionTemplate(tm); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); final List l = new ArrayList(); l.add("test"); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { txControl.verify(); txControl.reset(); tx.isActive(); txControl.setReturnValue(true, 1); tx.begin(); txControl.setVoidCallable(1); tx.getRollbackOnly(); txControl.setReturnValue(false, 2); tx.commit(); txControl.setVoidCallable(2); txControl.replay(); JdoTemplate jt = new JdoTemplate(pmf); jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { return null; } }); return tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { pm2.flush(); return l; } }); } }); } }); assertTrue("Correct result list", result == l); assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); TransactionSynchronizationManager.unbindResource(pmf); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); } public void testJtaTransactionCommit() throws Exception { MockControl utControl = MockControl.createControl(UserTransaction.class); UserTransaction ut = (UserTransaction) utControl.getMock(); ut.getStatus(); utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); ut.begin(); utControl.setVoidCallable(1); ut.getStatus(); utControl.setReturnValue(Status.STATUS_ACTIVE, 2); ut.commit(); utControl.setVoidCallable(1); utControl.replay(); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.flush(); pmControl.setVoidCallable(2); pm.close(); pmControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); JtaTransactionManager ptm = new JtaTransactionManager(ut); TransactionTemplate tt = new TransactionTemplate(ptm); final List l = new ArrayList(); l.add("test"); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("JTA synchronizations active", TransactionSynchronizationManager.isSynchronizationActive()); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); JdoTemplate jt = new JdoTemplate(pmf); jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); pm2.flush(); return l; } }); Object result = jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); pm2.flush(); return l; } }); assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); return result; } }); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Correct result list", result == l); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); utControl.verify(); } public void testParticipatingJtaTransactionWithWithRequiresNewAndPrebound() throws Exception { final MockControl utControl = MockControl.createControl(UserTransaction.class); final UserTransaction ut = (UserTransaction) utControl.getMock(); final MockControl tmControl = MockControl.createControl(TransactionManager.class); final TransactionManager tm = (TransactionManager) tmControl.getMock(); ut.getStatus(); utControl.setReturnValue(Status.STATUS_NO_TRANSACTION, 1); ut.begin(); utControl.setVoidCallable(1); utControl.replay(); pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 1); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.flush(); pmControl.setVoidCallable(1); pm.close(); pmControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); JtaTransactionManager ptm = new JtaTransactionManager(ut, tm); final TransactionTemplate tt = new TransactionTemplate(ptm); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); final List l = new ArrayList(); l.add("test"); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { try { utControl.verify(); utControl.reset(); ut.getStatus(); utControl.setReturnValue(Status.STATUS_ACTIVE, 1); MockJtaTransaction transaction = new MockJtaTransaction(); tm.suspend(); tmControl.setReturnValue(transaction, 1); ut.begin(); utControl.setVoidCallable(1); ut.getStatus(); utControl.setReturnValue(Status.STATUS_ACTIVE, 4); ut.commit(); utControl.setVoidCallable(2); tm.resume(transaction); tmControl.setVoidCallable(1); utControl.replay(); tmControl.replay(); } catch (Exception ex) { } JdoTemplate jt = new JdoTemplate(pmf); jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { return null; } }); return tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { pm2.flush(); return l; } }); } }); } }); assertTrue("Correct result list", result == l); assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); TransactionSynchronizationManager.unbindResource(pmf); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); utControl.verify(); } public void testTransactionCommitWithPropagationSupports() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.close(); pmControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); TransactionTemplate tt = new TransactionTemplate(tm); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); final List l = new ArrayList(); l.add("test"); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Is not new transaction", !status.isNewTransaction()); JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm) { return l; } }); } }); assertTrue("Correct result list", result == l); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); } public void testInvalidIsolation() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 1); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(null, 1); pm.close(); pmControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); TransactionTemplate tt = new TransactionTemplate(tm); tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE); try { tt.execute(new TransactionCallbackWithoutResult() { protected void doInTransactionWithoutResult(TransactionStatus status) { } }); fail("Should have thrown InvalidIsolationLevelException"); } catch (InvalidIsolationLevelException ex) { // expected } } public void testTransactionCommitWithPrebound() { pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pm.currentTransaction(); pmControl.setReturnValue(tx, 3); tx.isActive(); txControl.setReturnValue(false, 1); tx.begin(); txControl.setVoidCallable(1); tx.getRollbackOnly(); txControl.setReturnValue(false, 1); tx.commit(); txControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); txControl.replay(); PlatformTransactionManager tm = new JdoTransactionManager(pmf); TransactionTemplate tt = new TransactionTemplate(tm); final List l = new ArrayList(); l.add("test"); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm)); assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm) { return l; } }); } }); assertTrue("Correct result list", result == l); assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); TransactionSynchronizationManager.unbindResource(pmf); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); } public void testTransactionCommitWithDataSource() throws SQLException { MockControl dsControl = MockControl.createControl(DataSource.class); final DataSource ds = (DataSource) dsControl.getMock(); MockControl dialectControl = MockControl.createControl(JdoDialect.class); JdoDialect dialect = (JdoDialect) dialectControl.getMock(); MockControl conControl = MockControl.createControl(Connection.class); final Connection con = (Connection) conControl.getMock(); ConnectionHandle conHandle = new SimpleConnectionHandle(con); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 3); pm.close(); pmControl.setVoidCallable(1); TransactionTemplate tt = new TransactionTemplate(); dialect.beginTransaction(tx, tt); dialectControl.setReturnValue(null, 1); dialect.getJdbcConnection(pm, false); dialectControl.setReturnValue(conHandle, 1); dialect.releaseJdbcConnection(conHandle, pm); dialectControl.setVoidCallable(1); dialect.cleanupTransaction(null); dialectControl.setVoidCallable(1); tx.getRollbackOnly(); txControl.setReturnValue(false, 1); tx.commit(); txControl.setVoidCallable(1); pmfControl.replay(); dsControl.replay(); dialectControl.replay(); pmControl.replay(); txControl.replay(); conControl.replay(); JdoTransactionManager tm = new JdoTransactionManager(); tm.setPersistenceManagerFactory(pmf); tm.setDataSource(ds); tm.setJdoDialect(dialect); tt.setTransactionManager(tm); final List l = new ArrayList(); l.add("test"); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Has thread con", TransactionSynchronizationManager.hasResource(ds)); JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm) { return l; } }); } }); assertTrue("Correct result list", result == l); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); dsControl.verify(); dialectControl.verify(); conControl.verify(); } public void testTransactionCommitWithAutoDetectedDataSource() throws SQLException { MockControl dsControl = MockControl.createControl(DataSource.class); final DataSource ds = (DataSource) dsControl.getMock(); MockControl dialectControl = MockControl.createControl(JdoDialect.class); JdoDialect dialect = (JdoDialect) dialectControl.getMock(); MockControl conControl = MockControl.createControl(Connection.class); final Connection con = (Connection) conControl.getMock(); ConnectionHandle conHandle = new SimpleConnectionHandle(con); pmfControl.reset(); pmf.getConnectionFactory(); pmfControl.setReturnValue(ds, 2); con.getMetaData(); conControl.setReturnValue(null, 1); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 3); pm.close(); pmControl.setVoidCallable(1); TransactionTemplate tt = new TransactionTemplate(); dialect.beginTransaction(tx, tt); dialectControl.setReturnValue(null, 1); dialect.getJdbcConnection(pm, false); dialectControl.setReturnValue(conHandle, 1); dialect.releaseJdbcConnection(conHandle, pm); dialectControl.setVoidCallable(1); dialect.cleanupTransaction(null); dialectControl.setVoidCallable(1); tx.getRollbackOnly(); txControl.setReturnValue(false, 1); tx.commit(); txControl.setVoidCallable(1); pmfControl.replay(); dsControl.replay(); dialectControl.replay(); pmControl.replay(); txControl.replay(); conControl.replay(); JdoTransactionManager tm = new JdoTransactionManager(); tm.setPersistenceManagerFactory(pmf); tm.setJdoDialect(dialect); tm.afterPropertiesSet(); tt.setTransactionManager(tm); final List l = new ArrayList(); l.add("test"); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Has thread con", TransactionSynchronizationManager.hasResource(ds)); JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm) { return l; } }); } }); assertTrue("Correct result list", result == l); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); dsControl.verify(); dialectControl.verify(); conControl.verify(); } public void testTransactionCommitWithAutoDetectedDataSourceAndNoConnection() throws SQLException { MockControl dsControl = MockControl.createControl(DataSource.class); final DataSource ds = (DataSource) dsControl.getMock(); MockControl dialectControl = MockControl.createControl(JdoDialect.class); final JdoDialect dialect = (JdoDialect) dialectControl.getMock(); MockControl conControl = MockControl.createControl(Connection.class); pmfControl.reset(); pmf.getConnectionFactory(); pmfControl.setReturnValue(ds, 1); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 3); pm.flush(); pmControl.setVoidCallable(1); pm.close(); pmControl.setVoidCallable(1); TransactionTemplate tt = new TransactionTemplate(); dialect.beginTransaction(tx, tt); dialectControl.setReturnValue(null, 1); dialect.getJdbcConnection(pm, false); dialectControl.setReturnValue(null, 1); dialect.cleanupTransaction(null); dialectControl.setVoidCallable(1); tx.getRollbackOnly(); txControl.setReturnValue(false, 1); tx.commit(); txControl.setVoidCallable(1); pmfControl.replay(); dsControl.replay(); dialectControl.replay(); pmControl.replay(); txControl.replay(); conControl.replay(); JdoTransactionManager tm = new JdoTransactionManager(); tm.setPersistenceManagerFactory(pmf); tm.setJdoDialect(dialect); tm.afterPropertiesSet(); tt.setTransactionManager(tm); final List l = new ArrayList(); l.add("test"); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); JdoTemplate jt = new JdoTemplate(); jt.setPersistenceManagerFactory(pmf); jt.setJdoDialect(dialect); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { pm2.flush(); return l; } }); } }); assertTrue("Correct result list", result == l); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); dsControl.verify(); dialectControl.verify(); conControl.verify(); } public void testExistingTransactionWithPropagationNestedAndRollback() throws SQLException { doTestExistingTransactionWithPropagationNestedAndRollback(false); } public void testExistingTransactionWithManualSavepointAndRollback() throws SQLException { doTestExistingTransactionWithPropagationNestedAndRollback(true); } private void doTestExistingTransactionWithPropagationNestedAndRollback(final boolean manualSavepoint) throws SQLException { MockControl dsControl = MockControl.createControl(DataSource.class); final DataSource ds = (DataSource) dsControl.getMock(); MockControl dialectControl = MockControl.createControl(JdoDialect.class); JdoDialect dialect = (JdoDialect) dialectControl.getMock(); MockControl conControl = MockControl.createControl(Connection.class); final Connection con = (Connection) conControl.getMock(); MockControl mdControl = MockControl.createControl(DatabaseMetaData.class); DatabaseMetaData md = (DatabaseMetaData) mdControl.getMock(); MockControl spControl = MockControl.createControl(Savepoint.class); Savepoint sp = (Savepoint) spControl.getMock(); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 3); pm.flush(); pmControl.setVoidCallable(1); pm.close(); pmControl.setVoidCallable(1); md.supportsSavepoints(); mdControl.setReturnValue(true, 1); con.getMetaData(); conControl.setReturnValue(md, 1); con.setSavepoint(ConnectionHolder.SAVEPOINT_NAME_PREFIX + 1); conControl.setReturnValue(sp, 1); con.rollback(sp); conControl.setVoidCallable(1); final TransactionTemplate tt = new TransactionTemplate(); tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED); dialect.beginTransaction(tx, tt); dialectControl.setReturnValue(null, 1); ConnectionHandle conHandle = new SimpleConnectionHandle(con); dialect.getJdbcConnection(pm, false); dialectControl.setReturnValue(conHandle, 1); dialect.releaseJdbcConnection(conHandle, pm); dialectControl.setVoidCallable(1); dialect.cleanupTransaction(null); dialectControl.setVoidCallable(1); if (!manualSavepoint) { tx.isActive(); txControl.setReturnValue(true, 1); } tx.getRollbackOnly(); txControl.setReturnValue(false, 1); tx.commit(); txControl.setVoidCallable(1); pmfControl.replay(); dsControl.replay(); dialectControl.replay(); pmControl.replay(); txControl.replay(); conControl.replay(); mdControl.replay(); spControl.replay(); JdoTransactionManager tm = new JdoTransactionManager(); tm.setNestedTransactionAllowed(true); tm.setPersistenceManagerFactory(pmf); tm.setDataSource(ds); tm.setJdoDialect(dialect); tt.setTransactionManager(tm); final List l = new ArrayList(); l.add("test"); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); Object result = tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Has thread con", TransactionSynchronizationManager.hasResource(ds)); if (manualSavepoint) { Object savepoint = status.createSavepoint(); status.rollbackToSavepoint(savepoint); } else { tt.execute(new TransactionCallbackWithoutResult() { protected void doInTransactionWithoutResult(TransactionStatus status) { assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds)); status.setRollbackOnly(); } }); } JdoTemplate jt = new JdoTemplate(pmf); return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { pm2.flush(); return l; } }); } }); assertTrue("Correct result list", result == l); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("Hasn't thread con", !TransactionSynchronizationManager.hasResource(ds)); dsControl.verify(); dialectControl.verify(); conControl.verify(); mdControl.verify(); spControl.verify(); } public void testTransactionTimeoutWithJdoDialect() throws SQLException { doTestTransactionTimeoutWithJdoDialect(true); } public void testTransactionTimeoutWithJdoDialectAndPmProxy() throws SQLException { doTestTransactionTimeoutWithJdoDialect(false); } private void doTestTransactionTimeoutWithJdoDialect(final boolean exposeNativePm) throws SQLException { MockControl queryControl = MockControl.createControl(Query.class); Query query = (Query) queryControl.getMock(); MockControl dialectControl = MockControl.createControl(JdoDialect.class); final JdoDialect dialect = (JdoDialect) dialectControl.getMock(); TransactionTemplate tt = new TransactionTemplate(); pmf.getConnectionFactory(); pmfControl.setReturnValue(null, 2); pmf.getPersistenceManager(); pmfControl.setReturnValue(pm, 1); pm.currentTransaction(); pmControl.setReturnValue(tx, 3); dialect.beginTransaction(tx, tt); dialectControl.setReturnValue(null, 1); if (!exposeNativePm) { dialect.applyQueryTimeout(query, 10); } dialect.cleanupTransaction(null); dialectControl.setVoidCallable(1); pm.newQuery(TestBean.class); pmControl.setReturnValue(query, 1); pm.close(); pmControl.setVoidCallable(1); tx.getRollbackOnly(); txControl.setReturnValue(false, 1); tx.commit(); txControl.setVoidCallable(1); pmfControl.replay(); pmControl.replay(); txControl.replay(); queryControl.replay(); dialectControl.replay(); JdoTransactionManager tm = new JdoTransactionManager(pmf); tm.setJdoDialect(dialect); tt.setTransactionManager(tm); tt.setTimeout(10); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); tt.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { assertTrue("Has thread pm", TransactionSynchronizationManager.hasResource(pmf)); JdoTemplate jt = new JdoTemplate(pmf); jt.setJdoDialect(dialect); if (exposeNativePm) { jt.setExposeNativePersistenceManager(true); } return jt.execute(new JdoCallback() { public Object doInJdo(PersistenceManager pm2) { if (exposeNativePm) { assertSame(pm, pm2); } else { assertTrue(Proxy.isProxyClass(pm2.getClass())); } pm2.newQuery(TestBean.class); return null; } }); } }); assertTrue("Hasn't thread pm", !TransactionSynchronizationManager.hasResource(pmf)); assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive()); dialectControl.verify(); queryControl.verify(); } }