/* * Bitronix Transaction Manager * * Copyright (c) 2010, Bitronix Software. * * 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 bitronix.tm.mock; import bitronix.tm.BitronixTransactionManager; import bitronix.tm.TransactionManagerServices; import bitronix.tm.mock.events.*; import bitronix.tm.resource.common.XAPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.transaction.Status; import javax.transaction.Transaction; import javax.transaction.xa.XAResource; import java.sql.Connection; import java.sql.SQLException; import java.util.List; /** * * @author lorban */ public class NewJdbcStrangeUsageMockTest extends AbstractMockJdbcTest { private final static Logger log = LoggerFactory.getLogger(NewJdbcStrangeUsageMockTest.class); public void testDeferredReuse() throws Exception { if (log.isDebugEnabled()) log.debug("*** getting TM"); BitronixTransactionManager tm = TransactionManagerServices.getTransactionManager(); XAPool pool1 = getPool(poolingDataSource1); if (log.isDebugEnabled()) log.debug("*** before begin"); tm.begin(); if (log.isDebugEnabled()) log.debug("*** after begin"); assertEquals(POOL_SIZE, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** getting connection from DS1"); Connection connection1 = poolingDataSource1.getConnection(); connection1.createStatement(); assertEquals(POOL_SIZE -1, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** closing connection 1"); connection1.close(); assertEquals(POOL_SIZE -1, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** getting again connection from DS1"); connection1 = poolingDataSource1.getConnection(); connection1.createStatement(); assertEquals(POOL_SIZE -1, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** closing again connection 1"); connection1.close(); assertEquals(POOL_SIZE -1, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** committing"); tm.commit(); if (log.isDebugEnabled()) log.debug("*** TX is done"); assertEquals(POOL_SIZE, pool1.inPoolSize()); // check flow List orderedEvents = EventRecorder.getOrderedEvents(); log.info(EventRecorder.dumpToString()); assertEquals(11, orderedEvents.size()); int i=0; assertEquals(Status.STATUS_ACTIVE, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(DATASOURCE1_NAME, ((ConnectionDequeuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); assertEquals(XAResource.TMNOFLAGS, ((XAResourceStartEvent) orderedEvents.get(i++)).getFlag()); assertEquals(DATASOURCE1_NAME, ((ConnectionDequeuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); assertEquals(XAResource.TMSUCCESS, ((XAResourceEndEvent) orderedEvents.get(i++)).getFlag()); assertEquals(Status.STATUS_PREPARING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_PREPARED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_COMMITTING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(true, ((XAResourceCommitEvent) orderedEvents.get(i++)).isOnePhase()); assertEquals(Status.STATUS_COMMITTED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(DATASOURCE1_NAME, ((ConnectionQueuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); } public void testDeferredCannotReuse() throws Exception { if (log.isDebugEnabled()) log.debug("*** getting TM"); BitronixTransactionManager tm = TransactionManagerServices.getTransactionManager(); // Use DataSource2 because it does not have shared accessible connections XAPool pool2 = getPool(poolingDataSource2); if (log.isDebugEnabled()) log.debug("*** before begin"); tm.begin(); if (log.isDebugEnabled()) log.debug("*** after begin"); assertEquals(POOL_SIZE, pool2.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** getting connection 1 from DS1"); Connection connection1 = poolingDataSource2.getConnection(); connection1.createStatement(); assertEquals(POOL_SIZE -1, pool2.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** getting connection 2 from DS1"); Connection connection2 = poolingDataSource2.getConnection(); connection2.createStatement(); assertEquals(POOL_SIZE -2, pool2.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** closing connection 1"); connection1.close(); assertEquals(POOL_SIZE -2, pool2.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** closing connection 2"); connection2.close(); assertEquals(POOL_SIZE -2, pool2.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** committing"); tm.commit(); if (log.isDebugEnabled()) log.debug("*** TX is done"); assertEquals(POOL_SIZE, pool2.inPoolSize()); // check flow List orderedEvents = EventRecorder.getOrderedEvents(); log.info(EventRecorder.dumpToString()); assertEquals(17, orderedEvents.size()); int i=0; assertEquals(Status.STATUS_ACTIVE, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(DATASOURCE2_NAME, ((ConnectionDequeuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); assertEquals(XAResource.TMNOFLAGS, ((XAResourceStartEvent) orderedEvents.get(i++)).getFlag()); assertEquals(DATASOURCE2_NAME, ((ConnectionDequeuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); assertEquals(XAResource.TMNOFLAGS, ((XAResourceStartEvent) orderedEvents.get(i++)).getFlag()); assertEquals(XAResource.TMSUCCESS, ((XAResourceEndEvent) orderedEvents.get(i++)).getFlag()); assertEquals(XAResource.TMSUCCESS, ((XAResourceEndEvent) orderedEvents.get(i++)).getFlag()); assertEquals(Status.STATUS_PREPARING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(XAResource.XA_OK, ((XAResourcePrepareEvent) orderedEvents.get(i++)).getReturnCode()); assertEquals(XAResource.XA_OK, ((XAResourcePrepareEvent) orderedEvents.get(i++)).getReturnCode()); assertEquals(Status.STATUS_PREPARED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_COMMITTING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(false, ((XAResourceCommitEvent) orderedEvents.get(i++)).isOnePhase()); assertEquals(false, ((XAResourceCommitEvent) orderedEvents.get(i++)).isOnePhase()); assertEquals(Status.STATUS_COMMITTED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(DATASOURCE2_NAME, ((ConnectionQueuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); assertEquals(DATASOURCE2_NAME, ((ConnectionQueuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); } public void testConnectionCloseInDifferentContext() throws Exception { if (log.isDebugEnabled()) log.debug("*** getting TM"); BitronixTransactionManager tm = TransactionManagerServices.getTransactionManager(); if (log.isDebugEnabled()) log.debug("*** beginning"); tm.begin(); if (log.isDebugEnabled()) log.debug("*** getting connection from DS1"); Connection connection1 = poolingDataSource1.getConnection(); connection1.createStatement(); if (log.isDebugEnabled()) log.debug("*** getting connection from DS2"); Connection connection2 = poolingDataSource2.getConnection(); connection2.createStatement(); if (log.isDebugEnabled()) log.debug("*** closing connection 2"); connection2.close(); if (log.isDebugEnabled()) log.debug("*** committing"); tm.commit(); if (log.isDebugEnabled()) log.debug("*** TX is done"); if (log.isDebugEnabled()) log.debug("*** beginning"); tm.begin(); if (log.isDebugEnabled()) log.debug("*** closing connection 1"); connection1.close(); if (log.isDebugEnabled()) log.debug("*** committing"); tm.commit(); if (log.isDebugEnabled()) log.debug("*** TX is done"); // check flow List orderedEvents = EventRecorder.getOrderedEvents(); log.info(EventRecorder.dumpToString()); assertEquals(22, orderedEvents.size()); int i=0; assertEquals(Status.STATUS_ACTIVE, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(DATASOURCE1_NAME, ((ConnectionDequeuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); assertEquals(XAResource.TMNOFLAGS, ((XAResourceStartEvent) orderedEvents.get(i++)).getFlag()); assertEquals(DATASOURCE2_NAME, ((ConnectionDequeuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); assertEquals(XAResource.TMNOFLAGS, ((XAResourceStartEvent) orderedEvents.get(i++)).getFlag()); assertEquals(XAResource.TMSUCCESS, ((XAResourceEndEvent) orderedEvents.get(i++)).getFlag()); assertEquals(XAResource.TMSUCCESS, ((XAResourceEndEvent) orderedEvents.get(i++)).getFlag()); assertEquals(Status.STATUS_PREPARING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(XAResource.XA_OK, ((XAResourcePrepareEvent) orderedEvents.get(i++)).getReturnCode()); assertEquals(XAResource.XA_OK, ((XAResourcePrepareEvent) orderedEvents.get(i++)).getReturnCode()); assertEquals(Status.STATUS_PREPARED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_COMMITTING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(false, ((XAResourceCommitEvent) orderedEvents.get(i++)).isOnePhase()); assertEquals(false, ((XAResourceCommitEvent) orderedEvents.get(i++)).isOnePhase()); assertEquals(Status.STATUS_COMMITTED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(DATASOURCE2_NAME, ((ConnectionQueuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); assertEquals(Status.STATUS_ACTIVE, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(DATASOURCE1_NAME, ((ConnectionQueuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); assertEquals(Status.STATUS_PREPARING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_PREPARED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_COMMITTING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_COMMITTED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); } public void testClosingSuspendedConnectionsInDifferentContext() throws Exception { if (log.isDebugEnabled()) log.debug("*** getting TM"); BitronixTransactionManager tm = TransactionManagerServices.getTransactionManager(); if (log.isDebugEnabled()) log.debug("*** before begin"); tm.begin(); XAPool pool1 = getPool(poolingDataSource1); assertEquals(POOL_SIZE, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** getting connection from DS1"); Connection connection1 = poolingDataSource1.getConnection(); connection1.createStatement(); assertEquals(POOL_SIZE -1, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** suspending"); Transaction t1 = tm.suspend(); assertEquals(POOL_SIZE -1, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** starting 2nd tx"); tm.begin(); assertEquals(POOL_SIZE -1, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** closing connection 1 too eagerly within another context"); try { // TODO: the ConnectionHandler tries to 'veto' the connection close here like the old pool did. // Instead, close the resource immediately or defer its release. connection1.close(); fail("successfully closed a connection participating in a global transaction, this should never be allowed"); } catch (SQLException ex) { assertEquals("cannot close a resource when its XAResource is taking part in an unfinished global transaction", ex.getCause().getMessage()); } assertEquals(POOL_SIZE -1, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** committing 2nd tx"); tm.commit(); assertEquals(POOL_SIZE -1, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** resuming"); tm.resume(t1); assertEquals(POOL_SIZE -1, pool1.inPoolSize()); if (log.isDebugEnabled()) log.debug("*** committing"); tm.commit(); if (log.isDebugEnabled()) log.debug("*** TX is done"); if (log.isDebugEnabled()) log.debug("*** closing connection 1"); connection1.close(); assertEquals(POOL_SIZE, pool1.inPoolSize()); // check flow List orderedEvents = EventRecorder.getOrderedEvents(); log.info(EventRecorder.dumpToString()); assertEquals(18, orderedEvents.size()); int i=0; assertEquals(Status.STATUS_ACTIVE, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(DATASOURCE1_NAME, ((ConnectionDequeuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); assertEquals(XAResource.TMNOFLAGS, ((XAResourceStartEvent) orderedEvents.get(i++)).getFlag()); assertEquals(XAResource.TMSUCCESS, ((XAResourceEndEvent) orderedEvents.get(i++)).getFlag()); assertEquals(Status.STATUS_ACTIVE, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_PREPARING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_PREPARED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_COMMITTING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_COMMITTED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(true, ((XAResourceIsSameRmEvent) orderedEvents.get(i++)).isSameRm()); assertEquals(XAResource.TMJOIN, ((XAResourceStartEvent) orderedEvents.get(i++)).getFlag()); assertEquals(XAResource.TMSUCCESS, ((XAResourceEndEvent) orderedEvents.get(i++)).getFlag()); assertEquals(Status.STATUS_PREPARING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_PREPARED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(Status.STATUS_COMMITTING, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(true, ((XAResourceCommitEvent) orderedEvents.get(i++)).isOnePhase()); assertEquals(Status.STATUS_COMMITTED, ((JournalLogEvent) orderedEvents.get(i++)).getStatus()); assertEquals(DATASOURCE1_NAME, ((ConnectionQueuedEvent) orderedEvents.get(i++)).getPooledConnectionImpl().getPoolingDataSource().getUniqueName()); } }