Package org.jboss.test.messaging.jms

Source Code of org.jboss.test.messaging.jms.XATest$MockServerSessionPool

/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software 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 software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
package org.jboss.test.messaging.jms;

import java.util.ArrayList;

import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ServerSession;
import javax.jms.ServerSessionPool;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.XAConnection;
import javax.jms.XAConnectionFactory;
import javax.jms.XASession;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;

import org.jboss.jms.client.JBossConnection;
import org.jboss.jms.client.JBossSession;
import org.jboss.jms.client.delegate.ClientConnectionDelegate;
import org.jboss.jms.client.delegate.DelegateSupport;
import org.jboss.jms.client.state.ConnectionState;
import org.jboss.jms.client.state.SessionState;
import org.jboss.jms.tx.ClientTransaction;
import org.jboss.jms.tx.LocalTx;
import org.jboss.jms.tx.MessagingXAResource;
import org.jboss.jms.tx.MessagingXid;
import org.jboss.jms.tx.ResourceManager;
import org.jboss.jms.tx.ResourceManagerFactory;
import org.jboss.logging.Logger;
import org.jboss.test.messaging.tools.ServerManagement;
import org.jboss.test.messaging.tools.container.InVMInitialContextFactory;
import org.jboss.test.messaging.tools.container.ServiceContainer;
import org.jboss.tm.TransactionManagerLocator;
import org.jboss.tm.TxUtils;

/**
*
* A XATestBase
*
* @author <a href="mailto:tim.fox@jboss.com">Tim Fox</a>
* @author <a href="mailto:clebert.suconic@jboss.com">Clebert Suconic</a>
* @author <a href="mailto:ataylor@redhat.com">Andy Taylor</a>
* @version <tt>$Revision: 1.1 $</tt>
*
* $Id$
*
*/
public class XATest extends JMSTestCase
{
   // Constants -----------------------------------------------------

   // Static --------------------------------------------------------

   // Attributes ----------------------------------------------------

   protected TransactionManager tm;

   protected Transaction suspendedTx;

   protected ServiceContainer sc;

   // Constructors --------------------------------------------------

   public XATest(final String name)
   {
      super(name);
   }

   // TestCase overrides -------------------------------------------

   public void setUp() throws Exception
   {
      super.setUp();

      ResourceManagerFactory.instance.clear();

      // Also need a local tx mgr if test is running remote
      if (ServerManagement.isRemote())
      {
         sc = new ServiceContainer("transaction");

         // Don't drop the tables again!
         sc.start(false);
      }

      InitialContext localIc = new InitialContext(InVMInitialContextFactory.getJNDIEnvironment());

      tm = (TransactionManager)localIc.lookup(ServiceContainer.TRANSACTION_MANAGER_JNDI_NAME);

      assertTrue(tm instanceof TransactionManagerImple);

      if (!ServerManagement.isRemote())
      {
         suspendedTx = tm.suspend();
      }
   }

   public void tearDown() throws Exception
   {
      if (TxUtils.isUncommitted(tm))
      {
         // roll it back
         try
         {
            tm.rollback();
         }
         catch (Throwable ignore)
         {
            // The connection will probably be closed so this may well throw an exception
         }
      }
      if (tm.getTransaction() != null)
      {
         Transaction tx = tm.suspend();
         if (tx != null)
         {
            log.warn("Transaction still associated with thread " + tx +
                     " at status " +
                     TxUtils.getStatusAsString(tx.getStatus()));
         }
      }

      if (suspendedTx != null)
      {
         tm.resume(suspendedTx);
      }

      if (ServerManagement.isRemote())
      {
         sc.stop();
      }

      super.tearDown();
   }

   // Public --------------------------------------------------------
   /*
   resource is not enlisted in tx

   do some work with tx W1

   enlist resource in tx

   do some more work W2

   delist resource from tx

   prepare tx

   commit tx

   validate that both sets of work W1 and W2 get applied.
    */
   // http://jira.jboss.com/jira/browse/JBMESSAGING-1221
   public void testMemoryLeakForLocalTXsWithWork() throws Exception
   {
      XAConnection conn = null;

      try
      {

         conn = cf.createXAConnection();

         JBossConnection jbConn = (JBossConnection)conn;

         ClientConnectionDelegate del = (ClientConnectionDelegate)jbConn.getDelegate();

         ConnectionState state = (ConnectionState)del.getState();

         ResourceManager rm = state.getResourceManager();

         // Create a session
         JBossSession sess1 = (JBossSession)conn.createXASession();
         DummyListener listener = new DummyListener();
         sess1.setMessageListener(listener);
         conn.start();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         tm.begin();

         Transaction trans = tm.getTransaction();
         trans.enlistResource(res1);
         trans.delistResource(res1, XAResource.TMSUCCESS);
         MessageProducer p = sess1.createProducer(queue1);
         MessageConsumer cons = sess1.createConsumer(queue1);
         conn.start();
         // send 10 messages
         for (int i = 0; i < 10; i++)
         {
            TextMessage message = sess1.createTextMessage("delistedwork" + i);
            p.send(message);
         }
         // now receive 5
         for (int i = 0; i < 5; i++)
         {
            TextMessage textMessage = (TextMessage)cons.receive();
            assertEquals("delistedwork" + i, textMessage.getText());
         }
         // once we enlist ensure that the 5 acks are merged ok, the first timne we do this there is nothing to merge in
         // the global tx
         // so all acks are just copied
         trans.enlistResource(res1);
         SessionState sstate = (SessionState)((DelegateSupport)sess1.getDelegate()).getState();
         ClientTransaction clientTransaction = rm.getTx(sstate.getCurrentTxId());
         assertEquals("to many session states", clientTransaction.getSessionStates().size(), 1);
         ClientTransaction.SessionTxState sessionTxState = (ClientTransaction.SessionTxState)clientTransaction.getSessionStates()
                                                                                                              .get(0);
         assertEquals("wrong number of acks", 5, sessionTxState.getAcks().size());

         trans.delistResource(res1, XAResource.TMSUCCESS);
         for (int i = 5; i < 10; i++)
         {
            TextMessage textMessage = (TextMessage)cons.receive();
            assertEquals("delistedwork" + i, textMessage.getText());
         }
         // now reenlist and make sure that there are now 10 acks, this time around a merge will be done with the first
         // 5 acks
         //
         trans.enlistResource(res1);

         clientTransaction = rm.getTx(sstate.getCurrentTxId());
         assertEquals("to many session states", clientTransaction.getSessionStates().size(), 1);
         sessionTxState = (ClientTransaction.SessionTxState)clientTransaction.getSessionStates().get(0);
         assertEquals("wrong number of acks", 10, sessionTxState.getAcks().size());

         tm.commit();

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }

      }

   }

   // http://jira.jboss.com/jira/browse/JBMESSAGING-1221
   public void testMemoryLeakForLocalTXsOnJoinOnePhase() throws Exception
   {
      XAConnection conn = null;

      try
      {

         conn = cf.createXAConnection();

         JBossConnection jbConn = (JBossConnection)conn;

         ClientConnectionDelegate del = (ClientConnectionDelegate)jbConn.getDelegate();

         ConnectionState state = (ConnectionState)del.getState();

         ResourceManager rm = state.getResourceManager();

         // Create a session
         XASession sess1 = conn.createXASession();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         byte[] branchQualifier = new byte[] { 1, 2, 3, 4, 5, 6, 0, 0, 0, 0 };
         byte[] globalTxId = new byte[] { 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 };
         int rmSizeBeforeStart = rm.size();
         Xid xid = new MessagingXid(branchQualifier, 12435, globalTxId);
         res1.start(xid, XAResource.TMNOFLAGS);
         res1.end(xid, XAResource.TMSUCCESS);
         int rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart + 1 == rmAfter);
         res1.start(xid, XAResource.TMJOIN);
         res1.end(xid, XAResource.TMSUCCESS);
         rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart + 1 == rmAfter);
         res1.commit(xid, true);
         rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart == rmAfter);
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }

      }

   }

   // http://jira.jboss.com/jira/browse/JBMESSAGING-1221
   public void testMemoryLeakForLocalTXsOnJoinTwoPhase() throws Exception
   {
      XAConnection conn = null;

      try
      {

         conn = cf.createXAConnection();

         JBossConnection jbConn = (JBossConnection)conn;

         ClientConnectionDelegate del = (ClientConnectionDelegate)jbConn.getDelegate();

         ConnectionState state = (ConnectionState)del.getState();

         ResourceManager rm = state.getResourceManager();

         // Create a session
         XASession sess1 = conn.createXASession();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         byte[] branchQualifier = new byte[] { 1, 2, 3, 4, 5, 6, 0, 0, 0, 0 };
         byte[] globalTxId = new byte[] { 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 };
         int rmSizeBeforeStart = rm.size();
         Xid xid = new MessagingXid(branchQualifier, 12435, globalTxId);
         res1.start(xid, XAResource.TMNOFLAGS);
         res1.end(xid, XAResource.TMSUCCESS);
         int rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart + 1 == rmAfter);
         res1.start(xid, XAResource.TMJOIN);
         res1.end(xid, XAResource.TMSUCCESS);
         rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart + 1 == rmAfter);
         res1.prepare(xid);
         res1.commit(xid, false);
         rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart == rmAfter);
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }

      }

   }

   // http://jira.jboss.com/jira/browse/JBMESSAGING-1221
   public void testMemoryLeakForLocalTXsOnResumeOnePhase() throws Exception
   {
      XAConnection conn = null;

      try
      {

         conn = cf.createXAConnection();

         JBossConnection jbConn = (JBossConnection)conn;

         ClientConnectionDelegate del = (ClientConnectionDelegate)jbConn.getDelegate();

         ConnectionState state = (ConnectionState)del.getState();

         ResourceManager rm = state.getResourceManager();

         // Create a session
         XASession sess1 = conn.createXASession();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         byte[] branchQualifier = new byte[] { 1, 2, 3, 4, 5, 6, 0, 0, 0, 0 };
         byte[] globalTxId = new byte[] { 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 };
         int rmSizeBeforeStart = rm.size();
         Xid xid = new MessagingXid(branchQualifier, 12435, globalTxId);
         res1.start(xid, XAResource.TMNOFLAGS);
         res1.end(xid, XAResource.TMSUCCESS);
         int rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart + 1 == rmAfter);
         res1.start(xid, XAResource.TMRESUME);
         res1.end(xid, XAResource.TMSUCCESS);
         rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart + 1 == rmAfter);
         res1.commit(xid, true);
         rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart == rmAfter);
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }

      }

   }

   // http://jira.jboss.com/jira/browse/JBMESSAGING-1221
   public void testMemoryLeakForLocalTXsOnJResumeTwoPhase() throws Exception
   {
      XAConnection conn = null;

      try
      {

         conn = cf.createXAConnection();

         JBossConnection jbConn = (JBossConnection)conn;

         ClientConnectionDelegate del = (ClientConnectionDelegate)jbConn.getDelegate();

         ConnectionState state = (ConnectionState)del.getState();

         ResourceManager rm = state.getResourceManager();

         // Create a session
         XASession sess1 = conn.createXASession();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         byte[] branchQualifier = new byte[] { 1, 2, 3, 4, 5, 6, 0, 0, 0, 0 };
         byte[] globalTxId = new byte[] { 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 };
         int rmSizeBeforeStart = rm.size();
         Xid xid = new MessagingXid(branchQualifier, 12435, globalTxId);
         res1.start(xid, XAResource.TMNOFLAGS);
         res1.end(xid, XAResource.TMSUCCESS);
         int rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart + 1 == rmAfter);
         res1.start(xid, XAResource.TMRESUME);
         res1.end(xid, XAResource.TMSUCCESS);
         rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart + 1 == rmAfter);
         res1.prepare(xid);
         res1.commit(xid, false);
         rmAfter = rm.size();
         assertTrue(rmSizeBeforeStart == rmAfter);
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }

      }

   }

   /* If there is no global tx present the send must behave as non transacted.
    * See http://www.jboss.com/index.html?module=bb&op=viewtopic&t=98577&postdays=0&postorder=asc&start=0
    * http://jira.jboss.com/jira/browse/JBMESSAGING-410
    * http://jira.jboss.com/jira/browse/JBMESSAGING-721
    * http://jira.jboss.org/jira/browse/JBMESSAGING-946
    */
   public void testSendNoGlobalTransaction() throws Exception
   {
      Transaction suspended = null;

      try
      {
         // make sure there's no active JTA transaction

         suspended = TransactionManagerLocator.getInstance().locate().suspend();

         // send a message to the queue using an XASession that's not enlisted in a global tx

         XAConnectionFactory xcf = (XAConnectionFactory)cf;

         XAConnection xconn = xcf.createXAConnection();

         XASession xs = xconn.createXASession();

         MessageProducer p = xs.createProducer(queue1);
         Message m = xs.createTextMessage("one");

         p.send(m);

         xconn.close();

         // receive the message
         Connection conn = cf.createConnection();
         conn.start();
         Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer c = s.createConsumer(queue1);
         TextMessage rm = (TextMessage)c.receive(1000);

         assertEquals("one", rm.getText());

         conn.close();
      }
      finally
      {
         if (suspended != null)
         {
            TransactionManagerLocator.getInstance().locate().resume(suspended);
         }
      }
   }

   /*
    * If messages are consumed using an XASession that is not enlisted in a transaction then the behaviour of the session
    * falls back to being AUTO_ACK - i.e. the messages will get acked immediately.
    *
    * There is one exception to this:
    *
    * For transactional delivery of messages in an MDB using the old container invoker (non JCA 1.5 inflow) the message
    * is received from the JMS provider *before* the MDB container has a chance to enlist the session in a transaction.
    * (see page 199 (chapter 5 JMS and Transactions, section "Application Server Integration" of Mark Little's book Java Transaction
    * processing for a discussion of how different app servers deal with this)
    * This is not a problem specific to JBoss and was solved with JCA 1.5 message inflow.
    * Consequently, if we detect the session has a distinguised session listener (which it will if using ASF) then the behaviour
    * is to fall back to being a local transacted session. Later on, when the session is enlisted the work done in the local tx
    * is converted to the global tx brach.
    *
    * We are testing the exceptional case here without a global tx here
    *
    * See http://www.jboss.com/index.html?module=bb&op=viewtopic&t=98577&postdays=0&postorder=asc&start=0
    * http://jira.jboss.com/jira/browse/JBMESSAGING-410
    * http://jira.jboss.com/jira/browse/JBMESSAGING-721
    * http://jira.jboss.org/jira/browse/JBMESSAGING-946
    *
    */
   public void testConsumeWithConnectionConsumerNoGlobalTransaction() throws Exception
   {
      // send a message to the queue

      Connection conn = cf.createConnection();
      Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
      MessageProducer p = s.createProducer(queue1);
      p.setDeliveryMode(DeliveryMode.PERSISTENT);
      Message m = s.createTextMessage("one");
      p.send(m);
      conn.close();

      // make sure there's no active JTA transaction

      Transaction suspended = tm.suspend();

      XAConnection xaconn = null;
      try
      {
         ObjectName queueMBean = new ObjectName("jboss.messaging.destination:service=Queue,name=Queue1");
         Integer count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(1, count.intValue());

         // using XA with a ConnectionConsumer (testing the transaction behavior under MDBs)

         XAConnectionFactory xacf = (XAConnectionFactory)cf;
         xaconn = xacf.createXAConnection();
         xaconn.start();
         XASession xasession = xaconn.createXASession();
         DummyListener listener = new DummyListener();
         xasession.setMessageListener(listener);

         ServerSessionPool pool = new MockServerSessionPool(xasession);

         xaconn.createConnectionConsumer(queue1, null, pool, 1);

         Thread.sleep(1000);
         assertEquals(1, listener.messages.size());

         // Message should still be on server
         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(1, count.intValue());

         XAResource resource = xasession.getXAResource();

         // Starts a new transaction
         tm.begin();

         Transaction trans = tm.getTransaction();

         JBossSession session = (JBossSession)xasession;
         SessionState state = (SessionState)((DelegateSupport)session.getDelegate()).getState();

         // Validates TX convertion
         assertTrue(state.getCurrentTxId() instanceof LocalTx);

         // Enlist the transaction... as supposed to be happening on JBossAS with the
         // default listener (enlist happening after message is received)
         trans.enlistResource(resource);

         // Validates TX convertion
         assertFalse(state.getCurrentTxId() instanceof LocalTx);

         trans.delistResource(resource, XAResource.TMSUCCESS);

         trans.commit();

         // After commit the message should be consumed
         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(0, count.intValue());
      }
      finally
      {
         if (xaconn != null)
         {
            xaconn.close();
         }
         if (suspended != null)
         {
            TransactionManagerLocator.getInstance().locate().resume(suspended);
         }
      }
   }

   /*
    * If messages are consumed using an XASession that is not enlisted in a transaction then the behaviour of the session
    * falls back to being AUTO_ACK - i.e. the messages will get acked immediately.
    *
    * There is one exception to this:
    *
    * For transactional delivery of messages in an MDB using the old container invoker (non JCA 1.5 inflow) the message
    * is received from the JMS provider *before* the MDB container has a chance to enlist the session in a transaction.
    * (see page 199 (chapter 5 JMS and Transactions, section "Application Server Integration" of Mark Little's book Java Transaction
    * processing for a discussion of how different app servers deal with this)
    * This is not a problem specific to JBoss and was solved with JCA 1.5 message inflow.
    * Consequently, if we detect the session has a distinguised session listener (which it will if using ASF) then the behaviour
    * is to fall back to being a local transacted session. Later on, when the session is enlisted the work done in the local tx
    * is converted to the global tx brach.
    *
    * We are testing the standard case without a global tx here
    *
    * See http://www.jboss.com/index.html?module=bb&op=viewtopic&t=98577&postdays=0&postorder=asc&start=0
    * http://jira.jboss.com/jira/browse/JBMESSAGING-410
    * http://jira.jboss.com/jira/browse/JBMESSAGING-721
    * http://jira.jboss.org/jira/browse/JBMESSAGING-946
    *
    */
   public void testConsumeWithoutConnectionConsumerNoGlobalTransaction() throws Exception
   {
      // send a message to the queue

      Connection conn = cf.createConnection();
      Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
      MessageProducer p = s.createProducer(queue1);
      p.setDeliveryMode(DeliveryMode.PERSISTENT);
      Message m = s.createTextMessage("one");
      p.send(m);
      conn.close();

      // make sure there's no active JTA transaction

      Transaction suspended = TransactionManagerLocator.getInstance().locate().suspend();

      try
      {
         ObjectName queueMBean = new ObjectName("jboss.messaging.destination:service=Queue,name=Queue1");
         Integer count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(1, count.intValue());

         XAConnectionFactory xcf = (XAConnectionFactory)cf;
         XAConnection xconn = xcf.createXAConnection();
         xconn.start();

         // no active JTA transaction here

         XASession xs = xconn.createXASession();

         MessageConsumer c = xs.createConsumer(queue1);

         // the message should be store unacked in the local session
         TextMessage rm = (TextMessage)c.receive(1000);

         assertEquals("one", rm.getText());

         // messages should be acked
         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(0, count.intValue());

         xconn.close();
      }
      finally
      {

         if (suspended != null)
         {
            TransactionManagerLocator.getInstance().locate().resume(suspended);
         }
      }
   }

   /*
    * If messages are consumed using an XASession that is not enlisted in a transaction then the behaviour of the session
    * falls back to being AUTO_ACK - i.e. the messages will get acked immediately.
    *
    * There is one exception to this:
    *
    * For transactional delivery of messages in an MDB using the old container invoker (non JCA 1.5 inflow) the message
    * is received from the JMS provider *before* the MDB container has a chance to enlist the session in a transaction.
    * (see page 199 (chapter 5 JMS and Transactions, section "Application Server Integration" of Mark Little's book Java Transaction
    * processing for a discussion of how different app servers deal with this)
    * This is not a problem specific to JBoss and was solved with JCA 1.5 message inflow.
    * Consequently, if we detect the session has a distinguised session listener (which it will if using ASF) then the behaviour
    * is to fall back to being a local transacted session. Later on, when the session is enlisted the work done in the local tx
    * is converted to the global tx brach.
    *
    * We are testing the case with a global tx here
    *
    * See http://www.jboss.com/index.html?module=bb&op=viewtopic&t=98577&postdays=0&postorder=asc&start=0
    * http://jira.jboss.com/jira/browse/JBMESSAGING-410
    * http://jira.jboss.com/jira/browse/JBMESSAGING-721
    * http://jira.jboss.org/jira/browse/JBMESSAGING-946
    *
    */
   public void testConsumeGlobalTransaction() throws Exception
   {
      XAConnection xaconn = null;

      try
      {
         // send a message to the queue

         Connection conn = cf.createConnection();
         Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer p = s.createProducer(queue1);
         p.setDeliveryMode(DeliveryMode.PERSISTENT);
         Message m = s.createTextMessage("one");
         p.send(m);
         conn.close();

         ObjectName queueMBean = new ObjectName("jboss.messaging.destination:service=Queue,name=Queue1");
         Integer count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(1, count.intValue());

         tm.begin();

         Transaction trans = tm.getTransaction();

         XAConnectionFactory xacf = (XAConnectionFactory)cf;

         xaconn = xacf.createXAConnection();

         xaconn.start();

         XASession xasession = xaconn.createXASession();

         XAResource resouce = xasession.getXAResource();

         trans.enlistResource(resouce);

         MessageConsumer consumer = xasession.createConsumer(queue1);

         TextMessage messageReceived = (TextMessage)consumer.receive(1000);

         assertNotNull(messageReceived);

         assertEquals("one", messageReceived.getText());

         assertNull(consumer.receive(1000));

         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");

         assertEquals(1, count.intValue());

         trans.delistResource(resouce, XAResource.TMSUCCESS);

         tm.rollback();

         tm.begin();
         trans = tm.getTransaction();
         trans.enlistResource(resouce);

         messageReceived = (TextMessage)consumer.receive(1000);

         assertNotNull(messageReceived);

         assertEquals("one", messageReceived.getText());

         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(1, count.intValue());

         trans.commit();

         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(0, count.intValue());

      }
      finally
      {
         if (xaconn != null)
         {
            xaconn.close();
         }
      }
   }

   /*
    *   This test will:
    *     - Send two messages over a producer
    *     - Receive one message over a consumer created used a XASession
    *     - Call Recover
    *     - Receive the second message
    *     - The queue should be empty after that
    *   Verifies if messages are sent ok and ack properly when recovery is called
    *      NOTE: To accomodate TCK tests where Session/Consumers are being used without transaction enlisting
    *            we are processing those cases as nonTransactional/AutoACK, however if the session is being used
    *            to process MDBs we will consider the LocalTransaction convertion and process those as the comment above
    *            This was done as per: http://jira.jboss.org/jira/browse/JBMESSAGING-946
    *
    */
   public void testRecoverOnXA() throws Exception
   {
      XAConnection xaconn = null;

      try
      {
         // send a message to the queue

         Connection conn = cf.createConnection();
         Session s = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer p = s.createProducer(queue1);
         p.setDeliveryMode(DeliveryMode.PERSISTENT);
         Message m = s.createTextMessage("one");
         p.send(m);
         m = s.createTextMessage("two");
         p.send(m);
         conn.close();

         ObjectName queueMBean = new ObjectName("jboss.messaging.destination:service=Queue,name=Queue1");
         Integer count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(2, count.intValue());

         XAConnectionFactory xacf = (XAConnectionFactory)cf;

         xaconn = xacf.createXAConnection();

         xaconn.start();

         XASession xasession = xaconn.createXASession();

         MessageConsumer consumer = xasession.createConsumer(queue1);

         TextMessage messageReceived = (TextMessage)consumer.receive(1000);

         assertNotNull(messageReceived);

         assertEquals("one", messageReceived.getText());

         xasession.recover();

         messageReceived = (TextMessage)consumer.receive(1000);

         assertEquals("two", messageReceived.getText());

         consumer.close();

         // I can't call xasession.close for this test as JCA layer would cache the session
         // So.. keep this close commented!
         // xasession.close();

         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(0, count.intValue());
      }
      finally
      {
         if (xaconn != null)
         {
            xaconn.close();
         }
      }
   }

   // See http://jira.jboss.com/jira/browse/JBMESSAGING-638
   public void testResourceManagerMemoryLeakOnCommit() throws Exception
   {
      XAConnection xaConn = null;

      try
      {
         xaConn = cf.createXAConnection();

         JBossConnection jbConn = (JBossConnection)xaConn;

         ClientConnectionDelegate del = (ClientConnectionDelegate)jbConn.getDelegate();

         ConnectionState state = (ConnectionState)del.getState();

         ResourceManager rm = state.getResourceManager();

         XASession xaSession = xaConn.createXASession();

         xaConn.start();

         XAResource res = xaSession.getXAResource();

         XAResource dummy = new DummyXAResource();

         for (int i = 0; i < 100; i++)
         {
            tm.begin();

            Transaction tx = tm.getTransaction();

            tx.enlistResource(res);

            tx.enlistResource(dummy);

            assertEquals(1, rm.size());

            tx.delistResource(res, XAResource.TMSUCCESS);

            tx.delistResource(dummy, XAResource.TMSUCCESS);

            tm.commit();
         }

         assertEquals(1, rm.size());

         xaConn.close();

         xaConn = null;

         assertEquals(0, rm.size());

      }
      finally
      {
         if (xaConn != null)
         {
            xaConn.close();
         }
      }
   }

   // See http://jira.jboss.com/jira/browse/JBMESSAGING-638
   public void testResourceManagerMemoryLeakOnRollback() throws Exception
   {
      XAConnection xaConn = null;

      try
      {
         xaConn = cf.createXAConnection();

         JBossConnection jbConn = (JBossConnection)xaConn;

         ClientConnectionDelegate del = (ClientConnectionDelegate)jbConn.getDelegate();

         ConnectionState state = (ConnectionState)del.getState();

         ResourceManager rm = state.getResourceManager();

         XASession xaSession = xaConn.createXASession();

         xaConn.start();

         XAResource res = xaSession.getXAResource();

         XAResource dummy = new DummyXAResource();

         for (int i = 0; i < 100; i++)
         {
            tm.begin();

            Transaction tx = tm.getTransaction();

            tx.enlistResource(res);

            tx.enlistResource(dummy);

            assertEquals(1, rm.size());

            tx.delistResource(res, XAResource.TMSUCCESS);

            tx.delistResource(dummy, XAResource.TMSUCCESS);

            tm.rollback();
         }

         assertEquals(1, rm.size());

         xaConn.close();

         xaConn = null;

         assertEquals(0, rm.size());

      }
      finally
      {
         if (xaConn != null)
         {
            xaConn.close();
         }
      }
   }

   // http://jira.jboss.com/jira/browse/JBMESSAGING-721
   public void testConvertFromLocalTx() throws Exception
   {
      Connection conn = null;

      XAConnection xaConn = null;

      try
      {

         // First send some messages to a queue

         ObjectName queueMBean = new ObjectName("jboss.messaging.destination:service=Queue,name=Queue1");
         Integer count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(0, count.intValue());

         conn = cf.createConnection();

         Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

         MessageProducer prod = sessSend.createProducer(queue1);

         TextMessage tm1 = sessSend.createTextMessage("message1");

         TextMessage tm2 = sessSend.createTextMessage("message2");

         prod.send(tm1);

         prod.send(tm2);

         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(2, count.intValue());

         xaConn = cf.createXAConnection();

         XASession xaSession = xaConn.createXASession();

         xaConn.start();

         DummyListener listener = new DummyListener();

         xaSession.setMessageListener(listener);

         ServerSessionPool pool = new MockServerSessionPool(xaSession);

         xaConn.createConnectionConsumer(queue1, null, pool, 1);

         Thread.sleep(1000);

         assertEquals(2, listener.messages.size());

         assertEquals("message1", ((TextMessage)listener.messages.get(0)).getText());
         assertEquals("message2", ((TextMessage)listener.messages.get(1)).getText());

         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(2, count.intValue());

         listener.messages.clear();

         // Now we enlist the session in an xa transaction

         XAResource res = xaSession.getXAResource();

         tm.begin();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);

         // This should cause the work done previously to be converted into work done in the xa transaction
         // this is what an MDB does
         // There is a difficulty in transactional delivery with an MDB.
         // The message is received from the destination and then sent to the mdb container so
         // it can call onMessage.
         // For transactional delivery the receipt of the message should be in a transaction but by the time
         // the mdb container is invoked the message has already been received it is too late - the message
         // has already been received and passed on (see page 199 (chapter 5 JMS and Transactions, section
         // "Application Server Integration"
         // of Mark Little's book Java Transaction processing
         // for a discussion of how different app serves deal with this)
         // The way jboss messaging (and jboss mq) deals with this is to convert any work done
         // prior to when the xasession is enlisted in the tx, into work done in the xa tx

         tx.delistResource(res, XAResource.TMSUCCESS);

         // Now rollback the tx - this should cause redelivery of the two messages
         tm.rollback();

         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(2, count.intValue());

         Thread.sleep(1000);

         assertEquals(2, listener.messages.size());

         listener.messages.clear();

         tm.begin();

         tx = tm.getTransaction();
         tx.enlistResource(res);

         tm.commit();

         Thread.sleep(1000);

         assertEquals(0, listener.messages.size());

         count = (Integer)ServerManagement.getAttribute(queueMBean, "MessageCount");
         assertEquals(0, count.intValue());

         assertNull(tm.getTransaction());
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }

         if (xaConn != null)
         {
            xaConn.close();
         }

         /* if (suspended != null)
          {
             tm.resume(suspended);
          }*/
      }
   }

   // http://jira.jboss.com/jira/browse/JBMESSAGING-721
   // Note: The behavior of this test was changed after http://jira.jboss.com/jira/browse/JBMESSAGING-946
   // When you have a XASession without a transaction enlisted we will behave the same way as non transactedSession,
   // AutoAck
   public void testTransactionIdSetAfterCommit() throws Exception
   {
      Connection conn = null;

      XAConnection xaConn = null;

      try
      {
         // First send some messages to a queue

         conn = cf.createConnection();

         Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

         MessageProducer prod = sessSend.createProducer(queue1);

         TextMessage tm1 = sessSend.createTextMessage("message1");

         TextMessage tm2 = sessSend.createTextMessage("message2");

         prod.send(tm1);

         prod.send(tm2);

         xaConn = cf.createXAConnection();

         XASession xaSession = xaConn.createXASession();

         xaConn.start();

         MessageConsumer cons = xaSession.createConsumer(queue1);

         // Now we enlist the session in an xa transaction

         XAResource res = xaSession.getXAResource();

         tm.begin();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);

         tx.delistResource(res, XAResource.TMSUCCESS);

         // Then we do a commit
         tm.commit();

         // I have changed where this begin was originally set
         // as when you don't have a resource enlisted, XASessions will act as
         // non transacted + AutoAck

         // And enlist again - this should convert the work done in the local tx
         // into the global branch

         tx = tm.getTransaction();

         tm.begin();

         tx = tm.getTransaction();
         tx.enlistResource(res);

         // Then we receive the messages outside the tx

         TextMessage rm1 = (TextMessage)cons.receive(1000);

         assertNotNull(rm1);

         assertEquals("message1", rm1.getText());

         TextMessage rm2 = (TextMessage)cons.receive(1000);

         assertNotNull(rm2);

         assertEquals("message2", rm2.getText());

         Message rm3 = cons.receive(1000);

         assertNull(rm3);

         tx.delistResource(res, XAResource.TMSUCCESS);

         // Now rollback the tx - this should cause redelivery of the two messages
         tx.rollback();

         rm1 = (TextMessage)cons.receive(1000);

         assertNotNull(rm1);

         assertEquals("message1", rm1.getText());

         rm2 = (TextMessage)cons.receive(1000);

         assertNotNull(rm2);

         assertEquals("message2", rm2.getText());

         rm3 = cons.receive(1000);

         assertNull(rm3);
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }

         if (xaConn != null)
         {
            xaConn.close();
         }
      }

   }

   // http://jira.jboss.com/jira/browse/JBMESSAGING-721
   public void testTransactionIdSetAfterRollback() throws Exception
   {
      Connection conn = null;

      XAConnection xaConn = null;

      try
      {
         // First send some messages to a queue

         conn = cf.createConnection();

         Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

         MessageProducer prod = sessSend.createProducer(queue1);

         TextMessage tm1 = sessSend.createTextMessage("message1");

         TextMessage tm2 = sessSend.createTextMessage("message2");

         prod.send(tm1);

         prod.send(tm2);

         xaConn = cf.createXAConnection();

         XASession xaSession = xaConn.createXASession();

         xaConn.start();

         MessageConsumer cons = xaSession.createConsumer(queue1);

         // Now we enlist the session in an xa transaction

         XAResource res = xaSession.getXAResource();

         tm.begin();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.delistResource(res, XAResource.TMSUCCESS);

         // Then we do a rollback
         tm.rollback();

         tm.begin();

         // And enlist again - the work should then be converted into the global tx branch

         // I have changed where this begin was originally set
         // as when you don't have a resource enlisted, XASessions will act as
         // non transacted + AutoAck

         tx = tm.getTransaction();

         tx.enlistResource(res);

         // Then we receive the messages outside the global tx

         TextMessage rm1 = (TextMessage)cons.receive(1000);

         assertNotNull(rm1);

         assertEquals("message1", rm1.getText());

         TextMessage rm2 = (TextMessage)cons.receive(1000);

         assertNotNull(rm2);

         assertEquals("message2", rm2.getText());

         Message rm3 = cons.receive(1000);

         assertNull(rm3);
         tx.delistResource(res, XAResource.TMSUCCESS);

         // Now rollback the tx - this should cause redelivery of the two messages
         tx.rollback();

         rm1 = (TextMessage)cons.receive(1000);

         assertNotNull(rm1);

         assertEquals("message1", rm1.getText());

         rm2 = (TextMessage)cons.receive(1000);

         assertNotNull(rm2);

         assertEquals("message2", rm2.getText());

         rm3 = cons.receive(1000);

         assertNull(rm3);
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }

         if (xaConn != null)
         {
            xaConn.close();
         }
      }
   }

   // See http://jira.jboss.org/jira/browse/JBMESSAGING-825
   // Need to test that ids with trailing zeros are dealt with properly - sybase has the habit
   // of truncating trailing zeros in varbinary columns
   public void testXidsWithTrailingZeros() throws Exception
   {
      if (!ServerManagement.isRemote())
      {
         return;
      }

      XAConnection conn1 = null;

      try
      {
         conn1 = cf.createXAConnection();

         XASession sess1 = conn1.createXASession();

         XAResource res1 = sess1.getXAResource();

         byte[] branchQualifier = new byte[] { 1, 2, 3, 4, 5, 6, 0, 0, 0, 0 };

         byte[] globalTxId = new byte[] { 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 };

         Xid trailing = new MessagingXid(branchQualifier, 12435, globalTxId);

         res1.start(trailing, XAResource.TMNOFLAGS);

         MessageProducer prod1 = sess1.createProducer(queue1);

         TextMessage tm1 = sess1.createTextMessage("testing1");

         prod1.send(tm1);

         res1.end(trailing, XAResource.TMSUCCESS);

         res1.prepare(trailing);

         // Now "crash" the server

         ServerManagement.stopServerPeer();

         ServerManagement.startServerPeer();

         deployAndLookupAdministeredObjects();

         conn1.close();

         conn1 = cf.createXAConnection();

         XAResource res = conn1.createXASession().getXAResource();

         Xid[] xids = res.recover(XAResource.TMSTARTRSCAN);
         assertEquals(1, xids.length);

         Xid[] xids2 = res.recover(XAResource.TMENDRSCAN);
         assertEquals(0, xids2.length);

         Xid trailing2 = xids[0];

         assertTrue(trailing.getFormatId() == trailing2.getFormatId());

         assertEqualByteArrays(trailing.getGlobalTransactionId(), trailing2.getGlobalTransactionId());

         assertEqualByteArrays(trailing.getBranchQualifier(), trailing2.getBranchQualifier());

         res.commit(trailing, false);
      }
      finally
      {
         removeAllMessages(queue1.getQueueName(), true, 0);

         if (conn1 != null)
         {
            try
            {
               conn1.close();
            }
            catch (Exception e)
            {
               // Ignore
            }
         }
      }
   }

   public void test2PCSendCommit1PCOptimization() throws Exception
   {
      // Since both resources have some RM, TM will probably use 1PC optimization

      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         conn = cf.createXAConnection();

         tm.begin();

         XASession sess = conn.createXASession();
         XAResource res = sess.getXAResource();

         XAResource res2 = new DummyXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         MessageProducer prod = sess.createProducer(queue1);
         prod.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
         Message m = sess.createTextMessage("XATest1");
         prod.send(queue1, m);
         m = sess.createTextMessage("XATest2");
         prod.send(queue1, m);

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.commit();

         conn2 = cf.createConnection();
         conn2.start();
         Session sessReceiver = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sessReceiver.createConsumer(queue1);
         TextMessage m2 = (TextMessage)cons.receive(1000);
         assertNotNull(m2);
         assertEquals("XATest1", m2.getText());
         m2 = (TextMessage)cons.receive(1000);
         assertNotNull(m2);
         assertEquals("XATest2", m2.getText());
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void test2PCSendCommit() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         conn = cf.createXAConnection();

         tm.begin();

         XASession sess = conn.createXASession();

         MessagingXAResource res = (MessagingXAResource)sess.getXAResource();
         XAResource res2 = new DummyXAResource();

         // To prevent 1PC optimization being used
         res.setPreventJoining(true);

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         MessageProducer prod = sess.createProducer(queue1);
         prod.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
         Message m = sess.createTextMessage("XATest1");
         prod.send(queue1, m);
         m = sess.createTextMessage("XATest2");
         prod.send(queue1, m);

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.commit();

         conn2 = cf.createConnection();
         conn2.start();
         Session sessReceiver = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sessReceiver.createConsumer(queue1);
         TextMessage m2 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m2);
         assertEquals("XATest1", m2.getText());
         m2 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m2);
         assertEquals("XATest2", m2.getText());
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void test2PCSendRollback1PCOptimization() throws Exception
   {
      // Since both resources have some RM, TM will probably use 1PC optimization

      XAConnection conn = null;
      Connection conn2 = null;
      try
      {
         conn = cf.createXAConnection();

         tm.begin();

         XASession sess = conn.createXASession();
         XAResource res = sess.getXAResource();

         XAResource res2 = new DummyXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         MessageProducer prod = sess.createProducer(queue1);
         prod.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
         Message m = sess.createTextMessage("XATest1");
         prod.send(queue1, m);
         m = sess.createTextMessage("XATest2");
         prod.send(queue1, m);

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.rollback();

         conn2 = cf.createConnection();
         conn2.start();
         Session sessReceiver = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sessReceiver.createConsumer(queue1);
         Message m2 = cons.receive(MIN_TIMEOUT);
         assertNull(m2);

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void test2PCSendFailOnPrepare() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;
      try
      {
         conn = cf.createXAConnection();

         tm.begin();

         XASession sess = conn.createXASession();
         MessagingXAResource res = (MessagingXAResource)sess.getXAResource();

         // prevent 1Pc optimisation
         res.setPreventJoining(true);

         XAResource res2 = new DummyXAResource(true);
         XAResource res3 = new DummyXAResource();
         XAResource res4 = new DummyXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);
         tx.enlistResource(res3);
         tx.enlistResource(res4);

         MessageProducer prod = sess.createProducer(queue1);
         prod.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
         Message m = sess.createTextMessage("XATest1");
         prod.send(queue1, m);
         m = sess.createTextMessage("XATest2");
         prod.send(queue1, m);

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);
         tx.delistResource(res3, XAResource.TMSUCCESS);
         tx.delistResource(res4, XAResource.TMSUCCESS);

         try
         {
            tm.commit();

            fail("should not get here");
         }
         catch (Exception e)
         {
            // We should expect this
         }

         conn2 = cf.createConnection();
         conn2.start();
         Session sessReceiver = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sessReceiver.createConsumer(queue1);
         Message m2 = cons.receive(MIN_TIMEOUT);
         assertNull(m2);
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void test2PCSendRollback() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;
      try
      {
         conn = cf.createXAConnection();

         tm.begin();

         XASession sess = conn.createXASession();
         MessagingXAResource res = (MessagingXAResource)sess.getXAResource();

         // prevent 1Pc optimisation
         res.setPreventJoining(true);

         XAResource res2 = new DummyXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         MessageProducer prod = sess.createProducer(queue1);
         prod.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
         Message m = sess.createTextMessage("XATest1");
         prod.send(queue1, m);
         m = sess.createTextMessage("XATest2");
         prod.send(queue1, m);

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.rollback();

         conn2 = cf.createConnection();
         conn2.start();
         Session sessReceiver = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sessReceiver.createConsumer(queue1);
         Message m2 = cons.receive(MIN_TIMEOUT);
         assertNull(m2);

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void test2PCReceiveCommit1PCOptimization() throws Exception
   {
      // Since both resources have some RM, TM will probably use 1PC optimization

      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         conn2 = cf.createConnection();
         conn2.start();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("XATest1");
         prod.send(m);
         m = sessProducer.createTextMessage("XATest2");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         XASession sess = conn.createXASession();
         XAResource res = sess.getXAResource();

         XAResource res2 = new DummyXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         MessageConsumer cons = sess.createConsumer(queue1);

         TextMessage m2 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(m2);
         assertEquals("XATest1", m2.getText());

         m2 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(m2);
         assertEquals("XATest2", m2.getText());

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.commit();

         // New tx
         tm.begin();
         tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         Message m3 = cons.receive(MIN_TIMEOUT);

         assertNull(m3);

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.commit();
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }

   }

   public void test2PCReceiveCommit() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         conn2 = cf.createConnection();
         conn2.start();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("XATest1");
         prod.send(m);
         m = sessProducer.createTextMessage("XATest2");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         XASession sess = conn.createXASession();
         MessagingXAResource res = (MessagingXAResource)sess.getXAResource();
         res.setPreventJoining(true);

         XAResource res2 = new DummyXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         MessageConsumer cons = sess.createConsumer(queue1);

         TextMessage m2 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(m2);
         assertEquals("XATest1", m2.getText());

         m2 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(m2);
         assertEquals("XATest2", m2.getText());

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.commit();

         // New tx
         tm.begin();
         tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         Message m3 = cons.receive(MIN_TIMEOUT);

         assertNull(m3);

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.commit();
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }

   }

   public void test2PCReceiveRollback1PCOptimization() throws Exception
   {
      // Since both resources have some RM, TM will probably use 1PC optimization

      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         conn2 = cf.createConnection();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("XATest1");
         prod.send(m);

         m = sessProducer.createTextMessage("XATest2");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         XASession sess = conn.createXASession();
         XAResource res = sess.getXAResource();

         XAResource res2 = new DummyXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         MessageConsumer cons = sess.createConsumer(queue1);

         TextMessage m2 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m2);
         assertEquals("XATest1", m2.getText());
         m2 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m2);
         assertEquals("XATest2", m2.getText());

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.rollback();

         // Message should be redelivered

         // New tx
         tm.begin();
         tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         TextMessage m3 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m3);
         assertEquals("XATest1", m3.getText());
         m3 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m3);
         assertEquals("XATest2", m3.getText());

         assertTrue(m3.getJMSRedelivered());

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.commit();
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void test2PCReceiveRollback() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         conn2 = cf.createConnection();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("XATest1");
         prod.send(m);

         m = sessProducer.createTextMessage("XATest2");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         XASession sess = conn.createXASession();
         MessagingXAResource res = (MessagingXAResource)sess.getXAResource();
         res.setPreventJoining(true);

         XAResource res2 = new DummyXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         MessageConsumer cons = sess.createConsumer(queue1);

         TextMessage m2 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m2);
         assertEquals("XATest1", m2.getText());
         m2 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m2);
         assertEquals("XATest2", m2.getText());

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.rollback();

         // Message should be redelivered

         // New tx
         tm.begin();
         tx = tm.getTransaction();
         tx.enlistResource(res);
         tx.enlistResource(res2);

         TextMessage m3 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m3);
         assertEquals("XATest1", m3.getText());
         m3 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m3);
         assertEquals("XATest2", m3.getText());

         assertTrue(m3.getJMSRedelivered());

         tx.delistResource(res, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.commit();

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }

   }

   public void test1PCSendCommit() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         conn = cf.createXAConnection();

         tm.begin();

         XASession sess = conn.createXASession();
         XAResource res = sess.getXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);

         MessageProducer prod = sess.createProducer(queue1);
         prod.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
         Message m = sess.createTextMessage("XATest1");
         prod.send(queue1, m);
         m = sess.createTextMessage("XATest2");
         prod.send(queue1, m);

         tx.delistResource(res, XAResource.TMSUCCESS);

         tm.commit();

         conn2 = cf.createConnection();
         conn2.start();
         Session sessReceiver = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sessReceiver.createConsumer(queue1);
         TextMessage m2 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m2);
         assertEquals("XATest1", m2.getText());
         m2 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(m2);
         assertEquals("XATest2", m2.getText());
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }

   }

   public void test1PCSendRollback() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;
      try
      {
         conn = cf.createXAConnection();

         tm.begin();

         XASession sess = conn.createXASession();
         XAResource res = sess.getXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);

         MessageProducer prod = sess.createProducer(queue1);
         prod.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
         Message m = sess.createTextMessage("XATest1");
         prod.send(queue1, m);
         m = sess.createTextMessage("XATest2");
         prod.send(queue1, m);

         tx.delistResource(res, XAResource.TMSUCCESS);

         tm.rollback();

         conn2 = cf.createConnection();
         conn2.start();
         Session sessReceiver = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sessReceiver.createConsumer(queue1);
         Message m2 = cons.receive(MIN_TIMEOUT);
         assertNull(m2);

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void test1PCReceiveCommit() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         conn2 = cf.createConnection();
         conn2.start();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("XATest1");
         prod.send(m);
         m = sessProducer.createTextMessage("XATest2");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         XASession sess = conn.createXASession();
         XAResource res = sess.getXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);

         MessageConsumer cons = sess.createConsumer(queue1);

         TextMessage m2 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(m2);
         assertEquals("XATest1", m2.getText());
         m2 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(m2);
         assertEquals("XATest2", m2.getText());

         tx.delistResource(res, XAResource.TMSUCCESS);

         tm.commit();

         // New tx
         tm.begin();
         tx = tm.getTransaction();
         tx.enlistResource(res);

         Message m3 = cons.receive(MIN_TIMEOUT);

         assertNull(m3);

         tx.delistResource(res, XAResource.TMSUCCESS);

         tm.commit();
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }

   }

   public void test1PCReceiveRollback() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         conn2 = cf.createConnection();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("XATest1");
         prod.send(m);
         m = sessProducer.createTextMessage("XATest2");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         XASession sess = conn.createXASession();
         XAResource res = sess.getXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res);

         MessageConsumer cons = sess.createConsumer(queue1);

         TextMessage m2 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(m2);
         assertEquals("XATest1", m2.getText());

         m2 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(m2);
         assertEquals("XATest2", m2.getText());

         tx.delistResource(res, XAResource.TMSUCCESS);

         tm.rollback();

         // Message should be redelivered

         // New tx
         tm.begin();
         tx = tm.getTransaction();
         tx.enlistResource(res);

         TextMessage m3 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(m3);
         assertEquals("XATest1", m3.getText());

         m3 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(m3);
         assertEquals("XATest2", m3.getText());

         assertTrue(m3.getJMSRedelivered());

         tx.delistResource(res, XAResource.TMSUCCESS);

         tm.commit();

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }

   }

   public void testMultipleSessionsOneTxCommitAcknowledge1PCOptimization() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      // Since both resources have some RM, TM will probably use 1PC optimization

      try
      {
         // First send 2 messages
         conn2 = cf.createConnection();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("jellyfish1");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish2");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         // Create 2 sessions and enlist them
         XASession sess1 = conn.createXASession();
         XAResource res1 = sess1.getXAResource();
         XASession sess2 = conn.createXASession();
         XAResource res2 = sess2.getXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res1);
         tx.enlistResource(res2);

         // Receive the messages, one on each consumer
         MessageConsumer cons1 = sess1.createConsumer(queue1);
         TextMessage r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);

         assertNotNull(r1);
         assertEquals("jellyfish1", r1.getText());

         cons1.close();

         MessageConsumer cons2 = sess2.createConsumer(queue1);
         TextMessage r2 = (TextMessage)cons2.receive(MAX_TIMEOUT);

         assertNotNull(r2);
         assertEquals("jellyfish2", r2.getText());

         tx.delistResource(res1, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         // commit
         tm.commit();

         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sess.createConsumer(queue1);
         conn2.start();

         TextMessage r3 = (TextMessage)cons.receive(MIN_TIMEOUT);
         assertNull(r3);

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }

   }

   public void testMultipleSessionsOneTxCommitAcknowledge() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         // First send 2 messages
         conn2 = cf.createConnection();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("jellyfish1");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish2");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         // Create 2 sessions and enlist them
         XASession sess1 = conn.createXASession();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         XASession sess2 = conn.createXASession();
         MessagingXAResource res2 = (MessagingXAResource)sess2.getXAResource();
         res1.setPreventJoining(true);
         res2.setPreventJoining(true);

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res1);
         tx.enlistResource(res2);

         // Receive the messages, one on each consumer
         MessageConsumer cons1 = sess1.createConsumer(queue1);
         TextMessage r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);

         assertNotNull(r1);
         assertEquals("jellyfish1", r1.getText());

         cons1.close();

         MessageConsumer cons2 = sess2.createConsumer(queue1);
         TextMessage r2 = (TextMessage)cons2.receive(MAX_TIMEOUT);

         assertNotNull(r2);
         assertEquals("jellyfish2", r2.getText());

         tx.delistResource(res1, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         // commit
         tm.commit();

         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sess.createConsumer(queue1);
         conn2.start();

         TextMessage r3 = (TextMessage)cons.receive(MIN_TIMEOUT);
         assertNull(r3);

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }

   }

   public void testMultipleSessionsOneTxRollbackAcknowledge1PCOptimization() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      // Since both resources have some RM, TM will probably use 1PC optimization

      try
      {
         // First send 2 messages
         conn2 = cf.createConnection();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("jellyfish1");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish2");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish3");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish4");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         // Create 2 sessions and enlist them
         XASession sess1 = conn.createXASession();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         XASession sess2 = conn.createXASession();
         MessagingXAResource res2 = (MessagingXAResource)sess2.getXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res1);
         tx.enlistResource(res2);

         // Receive the messages, two on each consumer
         MessageConsumer cons1 = sess1.createConsumer(queue1);
         TextMessage r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);

         assertNotNull(r1);
         assertEquals("jellyfish1", r1.getText());

         r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);

         assertNotNull(r1);
         assertEquals("jellyfish2", r1.getText());

         cons1.close();

         MessageConsumer cons2 = sess2.createConsumer(queue1);
         TextMessage r2 = (TextMessage)cons2.receive(MAX_TIMEOUT);

         assertNotNull(r2);
         assertEquals("jellyfish3", r2.getText());

         r2 = (TextMessage)cons2.receive(MAX_TIMEOUT);

         assertNotNull(r2);
         assertEquals("jellyfish4", r2.getText());

         cons2.close();

         // rollback

         tx.delistResource(res1, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.rollback();

         // Rollback causes cancel which is asynch
         Thread.sleep(1000);

         // We cannot assume anything about the order in which the transaction manager rollsback
         // the sessions - this is implementation dependent

         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sess.createConsumer(queue1);
         conn2.start();

         TextMessage r = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(r);

         boolean session1First = false;

         if (r.getText().equals("jellyfish1"))
         {
            session1First = true;
         }
         else if (r.getText().equals("jellyfish3"))
         {
            session1First = false;
         }
         else
         {
            fail("Unexpected message");
         }

         if (session1First)
         {
            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish2", r.getText());

            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish3", r.getText());

            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish4", r.getText());

         }
         else
         {
            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish4", r.getText());

            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish1", r.getText());

            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish2", r.getText());
         }

         r = (TextMessage)cons.receive(MIN_TIMEOUT);

         assertNull(r);

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }

   }

   public void testMultipleSessionsOneTxRollbackAcknowledge() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         // First send 2 messages
         conn2 = cf.createConnection();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("jellyfish1");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish2");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish3");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish4");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         // Create 2 sessions and enlist them
         XASession sess1 = conn.createXASession();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         XASession sess2 = conn.createXASession();
         MessagingXAResource res2 = (MessagingXAResource)sess2.getXAResource();
         res1.setPreventJoining(true);
         res2.setPreventJoining(true);

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res1);
         tx.enlistResource(res2);

         // Receive the messages, two on each consumer
         MessageConsumer cons1 = sess1.createConsumer(queue1);
         TextMessage r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);

         assertNotNull(r1);
         assertEquals("jellyfish1", r1.getText());

         r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);

         assertNotNull(r1);
         assertEquals("jellyfish2", r1.getText());

         cons1.close();

         // Cancel is asynch
         Thread.sleep(500);

         MessageConsumer cons2 = sess2.createConsumer(queue1);
         TextMessage r2 = (TextMessage)cons2.receive(MAX_TIMEOUT);

         assertNotNull(r2);
         assertEquals("jellyfish3", r2.getText());

         r2 = (TextMessage)cons2.receive(MAX_TIMEOUT);

         assertNotNull(r2);
         assertEquals("jellyfish4", r2.getText());

         // rollback

         cons2.close();

         tx.delistResource(res1, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         tm.rollback();

         // Rollback causes cancel which is asynch
         Thread.sleep(1000);

         // We cannot assume anything about the order in which the transaction manager rollsback
         // the sessions - this is implementation dependent

         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sess.createConsumer(queue1);
         conn2.start();

         TextMessage r = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(r);

         boolean session1First = false;

         if (r.getText().equals("jellyfish1"))
         {
            session1First = true;
         }
         else if (r.getText().equals("jellyfish3"))
         {
            session1First = false;
         }
         else
         {
            fail("Unexpected message");
         }

         if (session1First)
         {
            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish2", r.getText());

            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish3", r.getText());

            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish4", r.getText());

         }
         else
         {
            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish4", r.getText());

            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish1", r.getText());

            r = (TextMessage)cons.receive(MAX_TIMEOUT);

            assertNotNull(r);

            assertEquals("jellyfish2", r.getText());
         }

         r = (TextMessage)cons.receive(MIN_TIMEOUT);

         assertNull(r);
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void testMultipleSessionsOneTxRollbackAcknowledgeForceFailureInCommit() throws Exception
   {
      XAConnection conn = null;
      Connection conn2 = null;

      try
      {
         // First send 4 messages
         conn2 = cf.createConnection();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);

         Message m = sessProducer.createTextMessage("jellyfish1");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish2");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish3");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish4");
         prod.send(m);

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         XASession sess1 = conn.createXASession();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         DummyXAResource res2 = new DummyXAResource(true);
         res1.setPreventJoining(true);

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res1);
         tx.enlistResource(res2);

         MessageConsumer cons1 = sess1.createConsumer(queue1);
         TextMessage r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);

         assertNotNull(r1);
         assertEquals("jellyfish1", r1.getText());

         r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);

         assertNotNull(r1);
         assertEquals("jellyfish2", r1.getText());

         r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);

         assertNotNull(r1);
         assertEquals("jellyfish3", r1.getText());

         r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);

         assertNotNull(r1);
         assertEquals("jellyfish4", r1.getText());

         r1 = (TextMessage)cons1.receive(1000);

         assertNull(r1);

         cons1.close();

         // try and commit - and we're going to make the dummyxaresource throw an exception on commit,
         // which should cause rollback to be called on the other resource

         tx.delistResource(res1, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         // rollback will cause an attemp to deliver messages locally to the original consumers.
         // the original consumer has closed, so it will cancelled to the server
         // the server cancel is asynch, so we need to sleep for a bit to make sure it completes
         log.trace("Forcing failure");
         try
         {
            tm.commit();
            fail("should not get here");
         }
         catch (Exception e)
         {
            // We should expect this
         }

         Thread.sleep(1000);

         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sess.createConsumer(queue1);
         conn2.start();

         TextMessage r = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(r);

         assertEquals("jellyfish1", r.getText());

         r = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(r);

         assertEquals("jellyfish2", r.getText());

         r = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(r);

         assertEquals("jellyfish3", r.getText());

         r = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(r);

         assertEquals("jellyfish4", r.getText());

         r = (TextMessage)cons.receive(MIN_TIMEOUT);

         assertNull(r);
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }

   }

   public void testMultipleSessionsOneTxCommitSend1PCOptimization() throws Exception
   {
      // Since both resources have some RM, TM will probably use 1PC optimization

      XAConnection conn = null;

      Connection conn2 = null;

      try
      {
         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         // Create 2 sessions and enlist them
         XASession sess1 = conn.createXASession();
         XAResource res1 = sess1.getXAResource();
         XASession sess2 = conn.createXASession();
         XAResource res2 = sess2.getXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res1);
         tx.enlistResource(res2);

         // Send 2 messages - one from each session

         MessageProducer prod1 = sess1.createProducer(queue1);
         MessageProducer prod2 = sess2.createProducer(queue1);

         prod1.send(sess1.createTextMessage("echidna1"));
         prod2.send(sess2.createTextMessage("echidna2"));

         tx.delistResource(res1, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         // commit
         tm.commit();

         // Messages should be in queue

         conn2 = cf.createConnection();
         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sess.createConsumer(queue1);
         conn2.start();

         TextMessage r1 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(r1);
         assertEquals("echidna1", r1.getText());

         TextMessage r2 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(r2);
         assertEquals("echidna2", r2.getText());

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void testMultipleSessionsOneTxCommitSend() throws Exception
   {
      // Since both resources have some RM, TM will probably use 1PC optimization

      XAConnection conn = null;

      Connection conn2 = null;

      try
      {

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         // Create 2 sessions and enlist them
         XASession sess1 = conn.createXASession();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         XASession sess2 = conn.createXASession();
         MessagingXAResource res2 = (MessagingXAResource)sess2.getXAResource();
         res1.setPreventJoining(true);
         res2.setPreventJoining(true);

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res1);
         tx.enlistResource(res2);

         // Send 2 messages - one from each session

         MessageProducer prod1 = sess1.createProducer(queue1);
         MessageProducer prod2 = sess2.createProducer(queue1);

         prod1.send(sess1.createTextMessage("echidna1"));
         prod2.send(sess2.createTextMessage("echidna2"));

         tx.delistResource(res1, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         // commit
         tm.commit();

         // Messages should be in queue

         conn2 = cf.createConnection();
         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sess.createConsumer(queue1);
         conn2.start();

         TextMessage r1 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(r1);
         assertEquals("echidna1", r1.getText());

         TextMessage r2 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(r2);
         assertEquals("echidna2", r2.getText());

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }

      }

   }

   public void testMultipleSessionsOneTxRollbackSend1PCOptimization() throws Exception
   {
      // Since both resources have some RM, TM will probably use 1PC optimization

      XAConnection conn = null;

      Connection conn2 = null;

      try
      {
         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         // Create 2 sessions and enlist them
         XASession sess1 = conn.createXASession();
         XAResource res1 = sess1.getXAResource();
         XASession sess2 = conn.createXASession();
         XAResource res2 = sess2.getXAResource();

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res1);
         tx.enlistResource(res2);

         // Send 2 messages - one from each session

         MessageProducer prod1 = sess1.createProducer(queue1);
         MessageProducer prod2 = sess2.createProducer(queue1);

         prod1.send(sess1.createTextMessage("echidna1"));
         prod2.send(sess2.createTextMessage("echidna2"));

         tx.delistResource(res1, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         // rollback
         tm.rollback();

         // Messages should not be in queue

         conn2 = cf.createConnection();
         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sess.createConsumer(queue1);
         conn2.start();

         TextMessage r1 = (TextMessage)cons.receive(MIN_TIMEOUT);
         assertNull(r1);

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void testMultipleSessionsOneTxRollbackSend() throws Exception
   {
      XAConnection conn = null;

      Connection conn2 = null;

      try
      {

         conn = cf.createXAConnection();
         conn.start();

         tm.begin();

         // Create 2 sessions and enlist them
         XASession sess1 = conn.createXASession();
         MessagingXAResource res1 = (MessagingXAResource)sess1.getXAResource();
         XASession sess2 = conn.createXASession();
         MessagingXAResource res2 = (MessagingXAResource)sess2.getXAResource();
         res1.setPreventJoining(true);
         res2.setPreventJoining(true);

         Transaction tx = tm.getTransaction();
         tx.enlistResource(res1);
         tx.enlistResource(res2);

         // Send 2 messages - one from each session

         MessageProducer prod1 = sess1.createProducer(queue1);
         MessageProducer prod2 = sess2.createProducer(queue1);

         prod1.send(sess1.createTextMessage("echidna1"));
         prod2.send(sess2.createTextMessage("echidna2"));

         tx.delistResource(res1, XAResource.TMSUCCESS);
         tx.delistResource(res2, XAResource.TMSUCCESS);

         // rollback
         tm.rollback();

         // Messages should not be in queue

         conn2 = cf.createConnection();
         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageConsumer cons = sess.createConsumer(queue1);
         conn2.start();

         TextMessage r1 = (TextMessage)cons.receive(MIN_TIMEOUT);
         assertNull(r1);
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void testOneSessionTwoTransactionsCommitAcknowledge() throws Exception
   {
      XAConnection conn = null;

      Connection conn2 = null;

      try
      {
         // First send 2 messages
         conn2 = cf.createConnection();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("jellyfish1");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish2");
         prod.send(m);

         conn = cf.createXAConnection();

         // Create a session
         XASession sess1 = conn.createXASession();
         XAResource res1 = sess1.getXAResource();

         conn.start();
         MessageConsumer cons1 = sess1.createConsumer(queue1);

         tm.begin();

         Transaction tx1 = tm.getTransaction();
         tx1.enlistResource(res1);

         // Receive one message in one tx

         TextMessage r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);
         assertNotNull(r1);
         assertEquals("jellyfish1", r1.getText());

         // suspend the tx
         Transaction suspended = tm.suspend();

         tm.begin();

         Transaction tx2 = tm.getTransaction();
         tx2.enlistResource(res1);

         // Receive 2nd message in a different tx
         TextMessage r2 = (TextMessage)cons1.receive(MAX_TIMEOUT);
         assertNotNull(r2);
         assertEquals("jellyfish2", r2.getText());

         tx2.delistResource(res1, XAResource.TMSUCCESS);

         // commit this transaction
         tm.commit();

         // verify that no messages are available
         conn2.close();
         conn2 = cf.createConnection();
         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         conn2.start();
         MessageConsumer cons = sess.createConsumer(queue1);
         TextMessage r3 = (TextMessage)cons.receive(MIN_TIMEOUT);
         assertNull(r3);

         // now resume the first tx and then commit it
         tm.resume(suspended);

         tx1.delistResource(res1, XAResource.TMSUCCESS);

         tm.commit();
      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }
      }
   }

   public void testOneSessionTwoTransactionsRollbackAcknowledge() throws Exception
   {
      XAConnection conn = null;

      Connection conn2 = null;

      try
      {
         // First send 2 messages
         conn2 = cf.createConnection();
         Session sessProducer = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer prod = sessProducer.createProducer(queue1);
         Message m = sessProducer.createTextMessage("jellyfish1");
         prod.send(m);
         m = sessProducer.createTextMessage("jellyfish2");
         prod.send(m);

         conn = cf.createXAConnection();

         // Create a session
         XASession sess1 = conn.createXASession();
         XAResource res1 = sess1.getXAResource();

         conn.start();
         MessageConsumer cons1 = sess1.createConsumer(queue1);

         tm.begin();

         Transaction tx1 = tm.getTransaction();
         tx1.enlistResource(res1);

         // Receive one message in one tx

         TextMessage r1 = (TextMessage)cons1.receive(MAX_TIMEOUT);
         assertNotNull(r1);
         assertEquals("jellyfish1", r1.getText());

         // suspend the tx
         Transaction suspended = tm.suspend();

         tm.begin();

         Transaction tx2 = tm.getTransaction();
         tx2.enlistResource(res1);

         // Receive 2nd message in a different tx
         TextMessage r2 = (TextMessage)cons1.receive(MAX_TIMEOUT);
         assertNotNull(r2);
         assertEquals("jellyfish2", r2.getText());

         cons1.close();

         tx1.delistResource(res1, XAResource.TMSUCCESS);

         // rollback this transaction
         tm.rollback();

         // verify that second message is available
         conn2.close();
         conn2 = cf.createConnection();
         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         conn2.start();
         MessageConsumer cons = sess.createConsumer(queue1);

         TextMessage r3 = (TextMessage)cons.receive(MAX_TIMEOUT);

         assertNotNull(r3);
         assertEquals("jellyfish2", r3.getText());
         r3 = (TextMessage)cons.receive(MIN_TIMEOUT);
         assertNull(r3);

         // rollback the other tx
         tm.resume(suspended);
         tm.rollback();

         // Verify the first message is now available
         r3 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(r3);
         assertEquals("jellyfish1", r3.getText());
         r3 = (TextMessage)cons.receive(MIN_TIMEOUT);
         assertNull(r3);

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }

      }

   }

   public void testOneSessionTwoTransactionsCommitSend() throws Exception
   {
      XAConnection conn = null;

      Connection conn2 = null;

      try
      {
         conn = cf.createXAConnection();

         // Create a session
         XASession sess1 = conn.createXASession();
         XAResource res1 = sess1.getXAResource();

         MessageProducer prod1 = sess1.createProducer(queue1);

         tm.begin();

         Transaction tx1 = tm.getTransaction();
         tx1.enlistResource(res1);

         // Send a message
         prod1.send(sess1.createTextMessage("kangaroo1"));

         // suspend the tx
         Transaction suspended = tm.suspend();

         tm.begin();

         // Send another message in another tx using the same session
         Transaction tx2 = tm.getTransaction();
         tx2.enlistResource(res1);

         // Send a message
         prod1.send(sess1.createTextMessage("kangaroo2"));

         tx2.delistResource(res1, XAResource.TMSUCCESS);

         // commit this transaction
         tm.commit();

         // verify only kangaroo2 message is sent
         conn2 = cf.createConnection();
         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         conn2.start();
         MessageConsumer cons = sess.createConsumer(queue1);
         TextMessage r1 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(r1);
         assertEquals("kangaroo2", r1.getText());
         TextMessage r2 = (TextMessage)cons.receive(MIN_TIMEOUT);
         assertNull(r2);

         // now resume the first tx and then commit it
         tm.resume(suspended);

         tx1.delistResource(res1, XAResource.TMSUCCESS);

         tm.commit();

         // verify that the first text message is received
         TextMessage r3 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(r3);
         assertEquals("kangaroo1", r3.getText());

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }

      }

   }

   public void testOneSessionTwoTransactionsRollbackSend() throws Exception
   {
      XAConnection conn = null;

      Connection conn2 = null;

      try
      {

         conn = cf.createXAConnection();

         // Create a session
         XASession sess1 = conn.createXASession();
         XAResource res1 = sess1.getXAResource();

         MessageProducer prod1 = sess1.createProducer(queue1);

         tm.begin();

         Transaction tx1 = tm.getTransaction();
         tx1.enlistResource(res1);

         // Send a message
         prod1.send(sess1.createTextMessage("kangaroo1"));

         // suspend the tx
         Transaction suspended = tm.suspend();

         tm.begin();

         // Send another message in another tx using the same session
         Transaction tx2 = tm.getTransaction();
         tx2.enlistResource(res1);

         // Send a message
         prod1.send(sess1.createTextMessage("kangaroo2"));

         tx2.delistResource(res1, XAResource.TMSUCCESS);

         // rollback this transaction
         tm.rollback();

         // verify no messages are sent
         conn2 = cf.createConnection();
         Session sess = conn2.createSession(false, Session.AUTO_ACKNOWLEDGE);
         conn2.start();
         MessageConsumer cons = sess.createConsumer(queue1);
         TextMessage r1 = (TextMessage)cons.receive(MIN_TIMEOUT);

         assertNull(r1);

         // now resume the first tx and then commit it
         tm.resume(suspended);

         tx1.delistResource(res1, XAResource.TMSUCCESS);

         tm.commit();

         // verify that the first text message is received
         TextMessage r3 = (TextMessage)cons.receive(MAX_TIMEOUT);
         assertNotNull(r3);
         assertEquals("kangaroo1", r3.getText());

      }
      finally
      {
         if (conn != null)
         {
            conn.close();
         }
         if (conn2 != null)
         {
            conn2.close();
         }

      }

   }

   // Package protected ---------------------------------------------

   // Protected -----------------------------------------------------

   // Private -------------------------------------------------------

   private void assertEqualByteArrays(final byte[] b1, final byte[] b2)
   {
      log.info("b1 length: " + b1.length + " b2 length " + b2.length);

      if (b1.length != b2.length)
      {
         fail("Lengths not the same");
      }

      for (int i = 0; i < b1.length; i++)
      {
         if (b1[i] != b2[i])
         {
            fail("Not same at index " + i);
         }
      }
   }

   // Inner classes -------------------------------------------------

   static class DummyListener implements MessageListener
   {

      protected Logger log = Logger.getLogger(getClass());

      public ArrayList messages = new ArrayList();

      public void onMessage(final Message message)
      {
         log.info("Message received on DummyListener " + message);
         messages.add(message);
      }
   }

   static class MockServerSessionPool implements ServerSessionPool
   {
      private final ServerSession serverSession;

      MockServerSessionPool(final Session sess)
      {
         serverSession = new MockServerSession(sess);
      }

      public ServerSession getServerSession() throws JMSException
      {
         return serverSession;
      }
   }

   static class MockServerSession implements ServerSession
   {
      Session session;

      MockServerSession(final Session sess)
      {
         session = sess;
      }

      public Session getSession() throws JMSException
      {
         return session;
      }

      public void start() throws JMSException
      {
         session.run();
      }

   }

   static class DummyXAResource implements XAResource
   {
      boolean failOnPrepare;

      DummyXAResource()
      {
      }

      DummyXAResource(final boolean failOnPrepare)
      {
         this.failOnPrepare = failOnPrepare;
      }

      public void commit(final Xid arg0, final boolean arg1) throws XAException
      {
      }

      public void end(final Xid arg0, final int arg1) throws XAException
      {
      }

      public void forget(final Xid arg0) throws XAException
      {
      }

      public int getTransactionTimeout() throws XAException
      {
         return 0;
      }

      public boolean isSameRM(final XAResource arg0) throws XAException
      {
         return false;
      }

      public int prepare(final Xid arg0) throws XAException
      {
         if (failOnPrepare)
         {
            throw new XAException(XAException.XAER_RMFAIL);
         }
         return XAResource.XA_OK;
      }

      public Xid[] recover(final int arg0) throws XAException
      {
         return null;
      }

      public void rollback(final Xid arg0) throws XAException
      {
      }

      public boolean setTransactionTimeout(final int arg0) throws XAException
      {
         return false;
      }

      public void start(final Xid arg0, final int arg1) throws XAException
      {

      }

   }

}
TOP

Related Classes of org.jboss.test.messaging.jms.XATest$MockServerSessionPool

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.