[jboss-cvs] JBoss Messaging SVN: r1375 - in trunk: src/etc/server/default/deploy src/etc/xmdesc src/main/org/jboss/jms/client/container src/main/org/jboss/jms/client/delegate src/main/org/jboss/jms/client/remoting src/main/org/jboss/jms/client/state src/main/org/jboss/jms/message src/main/org/jboss/jms/server src/main/org/jboss/jms/server/destination src/main/org/jboss/jms/server/endpoint src/main/org/jboss/jms/tx src/main/org/jboss/messaging/core src/main/org/jboss/messaging/core/plugin src/main/org/jboss/messaging/core/plugin/contract src/main/org/jboss/messaging/core/plugin/postoffice src/main/org/jboss/messaging/core/plugin/postoffice/cluster tests/src/org/jboss/test/messaging/core/local tests/src/org/jboss/test/messaging/core/paging tests/src/org/jboss/test/messaging/core/plugin/base tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster tests/src/org/jboss/test/messaging/jms tests/src/org/jboss/test/messaging/tools/client

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu Sep 28 12:38:10 EDT 2006


Author: timfox
Date: 2006-09-28 12:37:36 -0400 (Thu, 28 Sep 2006)
New Revision: 1375

Added:
   trunk/tests/src/org/jboss/test/messaging/core/local/PagingFilteredQueueTestBase.java
   trunk/tests/src/org/jboss/test/messaging/core/paging/PagingStateTestBase.java
Modified:
   trunk/src/etc/server/default/deploy/clustered-mysql-persistence-service.xml
   trunk/src/etc/server/default/deploy/messaging-service.xml
   trunk/src/etc/server/default/deploy/mysql-persistence-service.xml
   trunk/src/etc/xmdesc/ServerPeer-xmbean.xml
   trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java
   trunk/src/main/org/jboss/jms/client/container/SessionAspect.java
   trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java
   trunk/src/main/org/jboss/jms/client/delegate/ClientConnectionFactoryDelegate.java
   trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java
   trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java
   trunk/src/main/org/jboss/jms/client/state/ConnectionState.java
   trunk/src/main/org/jboss/jms/message/MessageIdGeneratorFactory.java
   trunk/src/main/org/jboss/jms/server/ServerPeer.java
   trunk/src/main/org/jboss/jms/server/destination/DestinationServiceSupport.java
   trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java
   trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java
   trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java
   trunk/src/main/org/jboss/jms/tx/ResourceManagerFactory.java
   trunk/src/main/org/jboss/messaging/core/ChannelSupport.java
   trunk/src/main/org/jboss/messaging/core/plugin/ClusteredPostOfficeService.java
   trunk/src/main/org/jboss/messaging/core/plugin/DefaultPostOfficeService.java
   trunk/src/main/org/jboss/messaging/core/plugin/JDBCPersistenceManager.java
   trunk/src/main/org/jboss/messaging/core/plugin/JDBCShutdownLogger.java
   trunk/src/main/org/jboss/messaging/core/plugin/contract/ShutdownLogger.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/Binding.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultBinding.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultPostOffice.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/BindRequest.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/BindingInfo.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/CastMessagesCallback.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/CheckRequest.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/ClusteredQueue.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultClusteredBindings.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultClusteredPostOffice.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultRouter.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/LocalClusteredQueue.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/PostOfficeInternal.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/PullMessagesRequest.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/QueueStatsRequest.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/RemoteQueueStub.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/SendNodeIdRequest.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/SendTransactionRequest.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/TransactionId.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/TransactionRequest.java
   trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/UnbindRequest.java
   trunk/tests/src/org/jboss/test/messaging/core/plugin/base/ClusteringTestBase.java
   trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultClusteredPostOfficeTest.java
   trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultMessagePullPolicyTest.java
   trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultRouterTest.java
   trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/RedistributionTest.java
   trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java
   trunk/tests/src/org/jboss/test/messaging/tools/client/Colocated.java
Log:
Various fixes - sort out consumer id issue



Modified: trunk/src/etc/server/default/deploy/clustered-mysql-persistence-service.xml
===================================================================
--- trunk/src/etc/server/default/deploy/clustered-mysql-persistence-service.xml	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/etc/server/default/deploy/clustered-mysql-persistence-service.xml	2006-09-28 16:37:36 UTC (rev 1375)
@@ -67,7 +67,7 @@
       <attribute name="DataSource">java:/DefaultDS</attribute>
       <attribute name="CreateTablesOnStartup">true</attribute>
       <attribute name="SqlProperties"><![CDATA[
-CREATE_POSTOFFICE_TABLE=CREATE TABLE JMS_POSTOFFICE (POSTOFFICE_NAME VARCHAR(255), NODE_ID VARCHAR(255), QUEUE_NAME VARCHAR(1023), COND VARCHAR(1023), SELECTOR VARCHAR(1023), CHANNEL_ID BIGINT)
+CREATE_POSTOFFICE_TABLE=CREATE TABLE JMS_POSTOFFICE (POSTOFFICE_NAME VARCHAR(255), NODE_ID INTEGER, QUEUE_NAME VARCHAR(1023), COND VARCHAR(1023), SELECTOR VARCHAR(1023), CHANNEL_ID BIGINT)
 INSERT_BINDING=INSERT INTO JMS_POSTOFFICE (POSTOFFICE_NAME, NODE_ID, QUEUE_NAME, COND, SELECTOR, CHANNEL_ID) VALUES (?, ?, ?, ?, ?, ?)
 DELETE_BINDING=DELETE FROM JMS_POSTOFFICE WHERE POSTOFFICE_NAME=? AND NODE_ID=? AND QUEUE_NAME=?
 LOAD_BINDINGS=SELECT NODE_ID, QUEUE_NAME, COND, SELECTOR, CHANNEL_ID FROM JMS_POSTOFFICE WHERE POSTOFFICE_NAME  = ?
@@ -130,7 +130,7 @@
       <attribute name="DataSource">java:/DefaultDS</attribute>
       <attribute name="CreateTablesOnStartup">true</attribute>
       <attribute name="SqlProperties"><![CDATA[
-CREATE_POSTOFFICE_TABLE=CREATE TABLE JMS_POSTOFFICE (POSTOFFICE_NAME VARCHAR(255), NODE_ID VARCHAR(255), QUEUE_NAME VARCHAR(1023), COND VARCHAR(1023), SELECTOR VARCHAR(1023), CHANNEL_ID BIGINT)
+CREATE_POSTOFFICE_TABLE=CREATE TABLE JMS_POSTOFFICE (POSTOFFICE_NAME VARCHAR(255), NODE_ID INTEGER, QUEUE_NAME VARCHAR(1023), COND VARCHAR(1023), SELECTOR VARCHAR(1023), CHANNEL_ID BIGINT)
 INSERT_BINDING=INSERT INTO JMS_POSTOFFICE (POSTOFFICE_NAME, NODE_ID, QUEUE_NAME, COND, SELECTOR, CHANNEL_ID) VALUES (?, ?, ?, ?, ?, ?)
 DELETE_BINDING=DELETE FROM JMS_POSTOFFICE WHERE POSTOFFICE_NAME=? AND NODE_ID=? AND QUEUE_NAME=?
 LOAD_BINDINGS=SELECT NODE_ID, QUEUE_NAME, COND, SELECTOR, CHANNEL_ID FROM JMS_POSTOFFICE WHERE POSTOFFICE_NAME  = ?
@@ -205,7 +205,7 @@
       <attribute name="DataSource">java:/DefaultDS</attribute>
       <attribute name="CreateTablesOnStartup">true</attribute>
       <attribute name="SqlProperties"><![CDATA[
-      CREATE_STARTUP=CREATE TABLE JMS_STARTUP (NODE_ID VARCHAR(255) PRIMARY KEY)
+      CREATE_STARTUP=CREATE TABLE JMS_STARTUP (NODE_ID INTEGER PRIMARY KEY)
       SELECT_STARTUP=SELECT NODE_ID FROM JMS_STARTUP WHERE NODE_ID = ?
       DELETE_STARTUP=DELETE FROM JMS_STARTUP WHERE NODE_ID = ?
       INSERT_STARTUP=INSERT INTO JMS_STARTUP (NODE_ID) VALUES (?)

Modified: trunk/src/etc/server/default/deploy/messaging-service.xml
===================================================================
--- trunk/src/etc/server/default/deploy/messaging-service.xml	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/etc/server/default/deploy/messaging-service.xml	2006-09-28 16:37:36 UTC (rev 1375)
@@ -14,7 +14,7 @@
 
       <constructor>
          <!-- ServerPeerID -->
-         <arg type="java.lang.String" value="server.0" />
+         <arg type="int" value="0" />
          <!-- DefaultQueueJNDIContext -->
          <arg type="java.lang.String" value="/queue" />
          <!-- DefaultTopicJNDIContext -->

Modified: trunk/src/etc/server/default/deploy/mysql-persistence-service.xml
===================================================================
--- trunk/src/etc/server/default/deploy/mysql-persistence-service.xml	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/etc/server/default/deploy/mysql-persistence-service.xml	2006-09-28 16:37:36 UTC (rev 1375)
@@ -67,7 +67,7 @@
       <attribute name="DataSource">java:/DefaultDS</attribute>
       <attribute name="CreateTablesOnStartup">true</attribute>
       <attribute name="SqlProperties"><![CDATA[
-CREATE_POSTOFFICE_TABLE=CREATE TABLE JMS_POSTOFFICE (POSTOFFICE_NAME VARCHAR(255), NODE_ID VARCHAR(255), QUEUE_NAME VARCHAR(1023), COND VARCHAR(1023), SELECTOR VARCHAR(1023), CHANNEL_ID BIGINT)
+CREATE_POSTOFFICE_TABLE=CREATE TABLE JMS_POSTOFFICE (POSTOFFICE_NAME VARCHAR(255), NODE_ID INTEGER, QUEUE_NAME VARCHAR(1023), COND VARCHAR(1023), SELECTOR VARCHAR(1023), CHANNEL_ID BIGINT)
 INSERT_BINDING=INSERT INTO JMS_POSTOFFICE (POSTOFFICE_NAME, NODE_ID, QUEUE_NAME, COND, SELECTOR, CHANNEL_ID) VALUES (?, ?, ?, ?, ?, ?)
 DELETE_BINDING=DELETE FROM JMS_POSTOFFICE WHERE POSTOFFICE_NAME=? AND NODE_ID=? AND QUEUE_NAME=?
 LOAD_BINDINGS=SELECT NODE_ID, QUEUE_NAME, COND, SELECTOR, CHANNEL_ID FROM JMS_POSTOFFICE WHERE POSTOFFICE_NAME  = ?
@@ -84,11 +84,40 @@
       <attribute name="DataSource">java:/DefaultDS</attribute>
       <attribute name="CreateTablesOnStartup">true</attribute>
       <attribute name="SqlProperties"><![CDATA[
-CREATE_POSTOFFICE_TABLE=CREATE TABLE JMS_POSTOFFICE (POSTOFFICE_NAME VARCHAR(255), NODE_ID VARCHAR(255), QUEUE_NAME VARCHAR(1023), COND VARCHAR(1023), SELECTOR VARCHAR(1023), CHANNEL_ID BIGINT)
+CREATE_POSTOFFICE_TABLE=CREATE TABLE JMS_POSTOFFICE (POSTOFFICE_NAME VARCHAR(255), NODE_ID INTEGER, QUEUE_NAME VARCHAR(1023), COND VARCHAR(1023), SELECTOR VARCHAR(1023), CHANNEL_ID BIGINT)
 INSERT_BINDING=INSERT INTO JMS_POSTOFFICE (POSTOFFICE_NAME, NODE_ID, QUEUE_NAME, COND, SELECTOR, CHANNEL_ID) VALUES (?, ?, ?, ?, ?, ?)
 DELETE_BINDING=DELETE FROM JMS_POSTOFFICE WHERE POSTOFFICE_NAME=? AND NODE_ID=? AND QUEUE_NAME=?
 LOAD_BINDINGS=SELECT NODE_ID, QUEUE_NAME, COND, SELECTOR, CHANNEL_ID FROM JMS_POSTOFFICE WHERE POSTOFFICE_NAME  = ?
       ]]></attribute>
    </mbean>
+   
+   <mbean code="org.jboss.jms.server.plugin.JDBCJMSUserManagerService"
+      name="jboss.messaging:service=JMSUserManager"
+      xmbean-dd="xmdesc/JMSUserManager-xmbean.xml">
+      <depends>jboss.jca:service=DataSourceBinding,name=DefaultDS</depends>
+      <depends optional-attribute-name="TransactionManager">jboss:service=TransactionManager</depends>
+      <attribute name="DataSource">java:/DefaultDS</attribute>
+      <attribute name="CreateTablesOnStartup">true</attribute>
+      <attribute name="SqlProperties"><![CDATA[
+CREATE_USER_TABLE=CREATE TABLE JMS_USER (USERID VARCHAR(32) NOT NULL, PASSWD VARCHAR(32) NOT NULL, CLIENTID VARCHAR(128), PRIMARY KEY(USERID))
+CREATE_ROLE_TABLE=CREATE TABLE JMS_ROLE (ROLEID VARCHAR(32) NOT NULL, USERID VARCHAR(32) NOT NULL, PRIMARY KEY(USERID, ROLEID))
+SELECT_PRECONF_CLIENTID=SELECT CLIENTID FROM JMS_USER WHERE USERID=?
+      ]]></attribute>
+   </mbean>
 
+   <mbean code="org.jboss.messaging.core.plugin.JDBCShutdownLoggerService"
+      name="jboss.messaging:service=ShutdownLogger"
+      xmbean-dd="xmdesc/JDBCShutdownLogger-xmbean.xml">
+      <depends>jboss.jca:service=DataSourceBinding,name=DefaultDS</depends>
+      <depends optional-attribute-name="TransactionManager">jboss:service=TransactionManager</depends>
+      <attribute name="DataSource">java:/DefaultDS</attribute>
+      <attribute name="CreateTablesOnStartup">true</attribute>
+      <attribute name="SqlProperties"><![CDATA[
+      CREATE_STARTUP=CREATE TABLE JMS_STARTUP (NODE_ID INTEGER PRIMARY KEY)
+      SELECT_STARTUP=SELECT NODE_ID FROM JMS_STARTUP WHERE NODE_ID = ?
+      DELETE_STARTUP=DELETE FROM JMS_STARTUP WHERE NODE_ID = ?
+      INSERT_STARTUP=INSERT INTO JMS_STARTUP (NODE_ID) VALUES (?)
+      ]]></attribute>
+   </mbean>   
+
 </server>
\ No newline at end of file

Modified: trunk/src/etc/xmdesc/ServerPeer-xmbean.xml
===================================================================
--- trunk/src/etc/xmdesc/ServerPeer-xmbean.xml	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/etc/xmdesc/ServerPeer-xmbean.xml	2006-09-28 16:37:36 UTC (rev 1375)
@@ -12,7 +12,7 @@
       <name>ServerPeer</name>
       <parameter>
          <name>ServerPeerID</name>
-         <type>java.lang.String</type>
+         <type>int</type>
       </parameter>
       <parameter>
          <name>DefaultQueueJNDIContext</name>
@@ -119,7 +119,7 @@
    <attribute access="read-only" getMethod="getServerPeerID">
       <description>The ID of the ServerPeer. Must be unique per JBoss instance</description>
       <name>serverPeerID</name>
-      <type>java.lang.String</type>
+      <type>int</type>
    </attribute>
 
    <attribute access="read-only" getMethod="getDefaultQueueJNDIContext">

Modified: trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -72,6 +72,7 @@
       ConnectionState connectionState = (ConnectionState)sessionState.getParent();
       SessionDelegate sessionDelegate = (SessionDelegate)invocation.getTargetObject();
       ConsumerState consumerState = (ConsumerState)((DelegateSupport)consumerDelegate).getState();
+      int serverId = connectionState.getServerID();
       int consumerID = consumerState.getConsumerID();
       int prefetchSize = consumerState.getPrefetchSize();
       QueuedExecutor sessionExecutor = sessionState.getExecutor();
@@ -84,7 +85,7 @@
       sessionState.addCallbackHandler(messageHandler);
       
       CallbackManager cm = connectionState.getRemotingConnection().getCallbackManager();
-      cm.registerHandler(consumerID, messageHandler);
+      cm.registerHandler(serverId, consumerID, messageHandler);
          
       consumerState.setMessageCallbackHandler(messageHandler);
       
@@ -113,7 +114,7 @@
       sessionState.removeCallbackHandler(consumerState.getMessageCallbackHandler());
 
       CallbackManager cm = connectionState.getRemotingConnection().getCallbackManager();
-      cm.unregisterHandler(consumerState.getConsumerID());
+      cm.unregisterHandler(connectionState.getServerID(), consumerState.getConsumerID());
             
       return res;
    }      

Modified: trunk/src/main/org/jboss/jms/client/container/SessionAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/SessionAspect.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/client/container/SessionAspect.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -157,6 +157,8 @@
          {
             if (trace) { log.trace("acknowledging NON-transactionally"); }
 
+            log.info("****************ACKNOWLEDGING");
+            
             List acks = state.getToAck();
             AckInfo ack = (AckInfo)acks.get(0);
             sd.acknowledge(ack);

Modified: trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -81,7 +81,7 @@
       ClientConnectionDelegate connectionDelegate = (ClientConnectionDelegate)inv.invokeNext();
       connectionDelegate.init();
 
-      String serverID = cfd.getServerID();
+      int serverID = cfd.getServerID();
 
       ResourceManager rm = ResourceManagerFactory.instance.checkOutResourceManager(serverID);
       MessageIdGenerator gen =

Modified: trunk/src/main/org/jboss/jms/client/delegate/ClientConnectionFactoryDelegate.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/delegate/ClientConnectionFactoryDelegate.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/client/delegate/ClientConnectionFactoryDelegate.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -68,7 +68,7 @@
 
    protected String serverLocatorURI;
    protected Version serverVersion;
-   protected String serverID;
+   protected int serverID;
    protected boolean clientPing;
 
    private boolean trace;
@@ -78,7 +78,7 @@
    // Constructors --------------------------------------------------
 
    public ClientConnectionFactoryDelegate(int objectID, String serverLocatorURI,
-                                          Version serverVersion, String serverID,
+                                          Version serverVersion, int serverID,
                                           boolean clientPing)
    {
       super(objectID);
@@ -246,7 +246,7 @@
       return serverVersion;
    }
 
-   public String getServerID()
+   public int getServerID()
    {
       return serverID;
    }

Modified: trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -28,6 +28,7 @@
 
 import org.jboss.jms.server.endpoint.ClientDelivery;
 import org.jboss.jms.server.remoting.MessagingMarshallable;
+import org.jboss.logging.Logger;
 import org.jboss.remoting.InvocationRequest;
 import org.jboss.remoting.ServerInvocationHandler;
 import org.jboss.remoting.ServerInvoker;
@@ -49,6 +50,9 @@
  */
 public class CallbackManager implements ServerInvocationHandler
 {
+   private static final Logger log = Logger.getLogger(CallbackManager.class);
+
+   
    protected Map callbackHandlers;
 
    public CallbackManager()
@@ -56,16 +60,41 @@
       callbackHandlers = new ConcurrentReaderHashMap();
    }
    
-   public void registerHandler(int consumerID, MessageCallbackHandler handler)
+   public void registerHandler(int serverId, int consumerId, MessageCallbackHandler handler)
    {
-      callbackHandlers.put(new Integer(consumerID), handler);
+      Long lookup = calcLookup(serverId, consumerId);
+      
+      callbackHandlers.put(lookup, handler);
    }
    
-   public void unregisterHandler(int consumerID)
+   public void unregisterHandler(int serverId, int consumerId)
    {
-      callbackHandlers.remove(new Integer(consumerID));
+      Long lookup = calcLookup(serverId, consumerId);
+      
+      callbackHandlers.remove(lookup);
    }
    
+   private Long calcLookup(int serverId, int consumerId)
+   {
+      log.info("calculating lookup for server:" + serverId + " consumer:" + consumerId);
+      long id1 = serverId;
+      
+      id1 <<= 32;
+      
+      log.info("id1 is " + Long.toBinaryString(id1));
+            
+      long id2 = consumerId;
+      
+      log.info("id2 is " + Long.toBinaryString(id2));
+      
+      long lookup = id1 | id2;
+      
+      log.info("lookup is " + Long.toBinaryString(lookup));
+      
+      
+      return new Long(lookup);
+   }
+   
    public void addListener(InvokerCallbackHandler arg0)
    { 
    }
@@ -76,16 +105,20 @@
       
       ClientDelivery dr = (ClientDelivery)mm.getLoad();
       
-      int consumerID = dr.getConsumerID();
+      log.info("received message(s) from server " + dr.getServerId());
       
+      Long lookup = calcLookup(dr.getServerId(), dr.getConsumerId());
+      
+      log.info("lookup key is " + lookup);
+      
       List msgs = dr.getMessages();
 
       MessageCallbackHandler handler =
-         (MessageCallbackHandler)callbackHandlers.get(new Integer(consumerID));
+         (MessageCallbackHandler)callbackHandlers.get(lookup);
       
       if (handler == null)
       {
-         throw new IllegalStateException("Cannot find handler for consumer: " + consumerID);
+         throw new IllegalStateException("Cannot find handler for consumer: " + dr.getConsumerId() +  " and server " + dr.getServerId());
       }
       
       return new MessagingMarshallable(mm.getVersion(), handler.handleMessage(msgs));

Modified: trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -240,6 +240,8 @@
    {            
       if (trace) { log.trace(this + " receiving " + msgs.size() + " message(s) from the remoting layer"); }
                       
+      log.info(this + " receiving " + msgs.size() + " message(s) from the remoting layer");
+      
       synchronized (mainLock)
       {
          if (closed)

Modified: trunk/src/main/org/jboss/jms/client/state/ConnectionState.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/state/ConnectionState.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/client/state/ConnectionState.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -52,11 +52,11 @@
    
    private MessageIdGenerator idGenerator;
    
-   private String serverID;
+   private int serverID;
    
    private Version versionToUse;
     
-   public ConnectionState(String serverID, ConnectionDelegate delegate,
+   public ConnectionState(int serverID, ConnectionDelegate delegate,
                           JMSRemotingConnection remotingConnection, Version versionToUse,
                           ResourceManager rm, MessageIdGenerator gen)
       throws Exception
@@ -98,7 +98,7 @@
       return versionToUse;
    }
    
-   public String getServerID()
+   public int getServerID()
    {
       return serverID;
    }

Modified: trunk/src/main/org/jboss/jms/message/MessageIdGeneratorFactory.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/MessageIdGeneratorFactory.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/message/MessageIdGeneratorFactory.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -64,21 +64,23 @@
 
    // Public --------------------------------------------------------
 
-   public synchronized boolean containsMessageIdGenerator(String serverId)
+   public synchronized boolean containsMessageIdGenerator(int serverId)
    {
-      return holders.containsKey(serverId);
+      return holders.containsKey(new Integer(serverId));
    }
 
-   public synchronized MessageIdGenerator checkOutGenerator(String serverId,
+   public synchronized MessageIdGenerator checkOutGenerator(int serverId,
                                                             ConnectionFactoryDelegate cfd)
       throws JMSException
    {
-      Holder h = (Holder)holders.get(serverId);
+      Integer in = new Integer(serverId);
+      
+      Holder h = (Holder)holders.get(in);
 
       if (h == null)
       {
          h = new Holder(new MessageIdGenerator(cfd, BLOCK_SIZE));
-         holders.put(serverId, h);
+         holders.put(in, h);
       }
       else
       {
@@ -92,9 +94,11 @@
       return h.generator;
    }
 
-   public synchronized void checkInGenerator(String serverId)
+   public synchronized void checkInGenerator(int serverId)
    {
-      Holder h = (Holder)holders.get(serverId);
+      Integer in = new Integer(serverId);
+      
+      Holder h = (Holder)holders.get(in);
 
       if (h == null)
       {
@@ -105,7 +109,7 @@
 
       if (h.refCount == 0)
       {
-         holders.remove(serverId);
+         holders.remove(in);
          log.debug("checked in and removed MessageIdGenerator for " + serverId);
       }
       else

Modified: trunk/src/main/org/jboss/jms/server/ServerPeer.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/ServerPeer.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/server/ServerPeer.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -81,7 +81,7 @@
 
    private static final Logger log = Logger.getLogger(ServerPeer.class);
 
-   public static final String RECOVERABLE_CTX_NAME = "jms-recoverables";
+   //public static final String RECOVERABLE_CTX_NAME = "jms-recoverables";
 
    // The "subsystem" label this ServerPeer uses to register its ServerInvocationHandler with the
    // Remoting connector
@@ -91,7 +91,7 @@
 
    // Attributes ----------------------------------------------------
 
-   private String serverPeerID;
+   private int serverPeerID;
    private byte[] clientAOPConfig;
    private Version version;
 
@@ -102,7 +102,7 @@
 
    private boolean started;
 
-   private int objectIDSequence = Integer.MIN_VALUE + 1;
+   private int objectIDSequence = 1;
    
    private boolean crashed;
 
@@ -152,7 +152,7 @@
 
    // Constructors --------------------------------------------------
 
-   public ServerPeer(String serverPeerID,
+   public ServerPeer(int serverPeerID,
                      String defaultQueueJNDIContext,
                      String defaultTopicJNDIContext) throws Exception
    {
@@ -244,7 +244,7 @@
 
          initializeRemoting(mbeanServer);
    
-         createRecoverable();
+         //createRecoverable();
    
          started = true;
    
@@ -270,7 +270,7 @@
    
          started = false;
    
-         removeRecoverable();
+         //removeRecoverable();
    
          shutdownLogger.shutdown(serverPeerID);         
                   
@@ -405,7 +405,7 @@
       return version.getProviderMinorVersion();
    }
 
-   public String getServerPeerID()
+   public int getServerPeerID()
    {
       return serverPeerID;
    }
@@ -660,9 +660,7 @@
    {
       return shutdownLogger;
    }
-   
-   
-
+      
    public synchronized int getNextObjectID()
    {
       return objectIDSequence++;
@@ -706,12 +704,12 @@
     * order to obtain an XAResource so it can perform XA recovery.
     */
 
-   //Commented out until XA Recovery is complete
-
-   private void createRecoverable() throws Exception
-   {
-      //Disabled until XA Recovery is complete with Arjuna transaction integration
-
+//   //Commented out until XA Recovery is complete
+//
+//   private void createRecoverable() throws Exception
+//   {
+//      //Disabled until XA Recovery is complete with Arjuna transaction integration
+//
 //      InitialContext ic = new InitialContext();
 //
 //      int connFactoryID = connFactoryJNDIMapper.registerConnectionFactory(null, null);
@@ -737,24 +735,24 @@
 //      }
 //
 //      recCtx.rebind(this.serverPeerID, recoverable);
-   }
+//   }
 
-   private void removeRecoverable() throws Exception
-   {
-      InitialContext ic = new InitialContext();
+//   private void removeRecoverable() throws Exception
+//   {
+//      InitialContext ic = new InitialContext();
+//
+//      Context recCtx = null;
+//      try
+//      {
+//         recCtx = (Context)ic.lookup(RECOVERABLE_CTX_NAME);
+//         recCtx.unbind(serverPeerID);
+//      }
+//      catch (NamingException e)
+//      {
+//         //Ignore
+//      }
+//   }
 
-      Context recCtx = null;
-      try
-      {
-         recCtx = (Context)ic.lookup(RECOVERABLE_CTX_NAME);
-         recCtx.unbind(serverPeerID);
-      }
-      catch (NamingException e)
-      {
-         //Ignore
-      }
-   }
-
    private void initializeRemoting(MBeanServer mbeanServer) throws Exception
    {
       // We explicitly associate the datatype "jms" with the java SerializationManager

Modified: trunk/src/main/org/jboss/jms/server/destination/DestinationServiceSupport.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/destination/DestinationServiceSupport.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/server/destination/DestinationServiceSupport.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -65,7 +65,7 @@
    
    protected IdManager idm;
    
-   protected String nodeId;
+   protected int nodeId;
    
    private boolean createdProgrammatically;
    

Modified: trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -53,7 +53,11 @@
    
    private List msgs;
          
-   private int consumerID;
+   //We need to specify the server id too since different servers might have the
+   //same consumer id
+   private int serverId;
+   
+   private int consumerId;
     
    // Constructors --------------------------------------------------
    
@@ -61,11 +65,13 @@
    {      
    }
 
-   public ClientDelivery(List msgs, int consumerID)
+   public ClientDelivery(List msgs, int serverId, int consumerId)
    {
       this.msgs = msgs;
       
-      this.consumerID = consumerID;      
+      this.serverId = serverId;
+      
+      this.consumerId = consumerId;
    }
   
    // Streamable implementation
@@ -73,8 +79,10 @@
    
    public void write(DataOutputStream out) throws Exception
    {
-      out.writeInt(consumerID);
+      out.writeInt(serverId);
       
+      out.writeInt(consumerId);
+      
       out.writeInt(msgs.size());
       
       Iterator iter = msgs.iterator();
@@ -93,8 +101,10 @@
 
    public void read(DataInputStream in) throws Exception
    {
-      consumerID = in.readInt();
+      serverId = in.readInt();
       
+      consumerId = in.readInt();
+      
       int numMessages = in.readInt();
       
       msgs = new ArrayList(numMessages);
@@ -122,10 +132,15 @@
       return msgs;
    }
    
-   public int getConsumerID()
+   public int getServerId()
    {
-      return consumerID;
+      return serverId;
    }
+   
+   public int getConsumerId()
+   {
+      return consumerId;
+   }
 
    // Package protected ---------------------------------------------
    

Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -206,6 +206,8 @@
    {
       if (trace) { log.trace(this + " receives " + ref + " for delivery"); }
       
+      log.info(this + " receives " + ref + " for delivery");
+      
       // This is ok to have outside lock - is volatile
       if (bufferFull)
       {
@@ -509,6 +511,8 @@
    {  
       // acknowledge a delivery   
       Delivery d;
+      
+      log.info("acknowledging: " + messageID);
         
       synchronized (lock)
       {
@@ -755,12 +759,14 @@
 
          ServerConnectionEndpoint connection =
             ServerConsumerEndpoint.this.sessionEndpoint.getConnectionEndpoint();
+         
+         int serverId = connection.getServerPeer().getServerPeerID();
 
          try
          {
             if (trace) { log.trace(ServerConsumerEndpoint.this + " handing " + list.size() + " message(s) over to the remoting layer"); }
 
-            ClientDelivery del = new ClientDelivery(list, id);
+            ClientDelivery del = new ClientDelivery(list, serverId, id);
 
             // TODO How can we ensure that messages for the same consumer aren't delivered
             // concurrently to the same consumer on different threads?

Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -106,7 +106,7 @@
    private TransactionRepository tr;
    private PostOffice topicPostOffice;
    private PostOffice queuePostOffice;
-   private String nodeId;
+   private int nodeId;
    
    
    // Constructors --------------------------------------------------

Modified: trunk/src/main/org/jboss/jms/tx/ResourceManagerFactory.java
===================================================================
--- trunk/src/main/org/jboss/jms/tx/ResourceManagerFactory.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/jms/tx/ResourceManagerFactory.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -50,23 +50,25 @@
       holders = new HashMap();
    }
       
-   public synchronized boolean containsResourceManager(String serverID)
+   public synchronized boolean containsResourceManager(int serverID)
    {
-      return holders.containsKey(serverID);
+      return holders.containsKey(new Integer(serverID));
    }
    
    /**
     * @param serverID - server peer ID.
     */
-   public synchronized ResourceManager checkOutResourceManager(String serverID)
+   public synchronized ResourceManager checkOutResourceManager(int serverID)
    {
-      Holder h = (Holder)holders.get(serverID);
+      Integer in = new Integer(serverID);
       
+      Holder h = (Holder)holders.get(in);
+      
       if (h == null)
       {
          h = new Holder();
          
-         holders.put(serverID, h);
+         holders.put(in, h);
       }
       else
       {
@@ -76,10 +78,12 @@
       return h.rm;
    }
    
-   public synchronized void checkInResourceManager(String serverID)
+   public synchronized void checkInResourceManager(int serverID)
    {
-      Holder h = (Holder)holders.get(serverID);
+      Integer in = new Integer(serverID);
       
+      Holder h = (Holder)holders.get(in);
+      
       if (h == null)
       {
          throw new IllegalArgumentException("Cannot find resource manager for server: " + serverID);
@@ -89,7 +93,7 @@
       
       if (h.refCount == 0)
       {
-         holders.remove(serverID);
+         holders.remove(in);
       }      
    }
    

Modified: trunk/src/main/org/jboss/messaging/core/ChannelSupport.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/ChannelSupport.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/ChannelSupport.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -146,8 +146,11 @@
    {
       if (!active)
       {
+         log.info("Not active - ignoring ref");
          return null;
       }
+      
+      log.info("handling ref");
      
       checkClosed();
       
@@ -182,6 +185,8 @@
    {
       if (trace) { log.trace("acknowledging " + d + (tx == null ? " non-transactionally" : " transactionally in " + tx)); }
 
+      log.info("acknowledging " + d);
+      
       this.acknowledgeInternal(d, tx, true, false);
    }
    
@@ -523,6 +528,8 @@
     */
    protected void deliverInternal(boolean handle) throws Throwable
    {
+      log.info("in deliver internal");
+      
       try
       {
          // The iterator is used to iterate through the refs in the channel in the case that they
@@ -583,6 +590,8 @@
                   ref.incrementDeliveryCount();
 
                   Delivery del = router.handle(this, ref, null);
+                  
+                  log.info("router returned delivery " + del);
 
                   if (del == null)
                   {

Modified: trunk/src/main/org/jboss/messaging/core/plugin/ClusteredPostOfficeService.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/ClusteredPostOfficeService.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/ClusteredPostOfficeService.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -215,7 +215,7 @@
          
          QueuedExecutorPool pool = serverPeer.getQueuedExecutorPool();
                   
-         String nodeId = serverPeer.getServerPeerID();
+         int nodeId = serverPeer.getServerPeerID();
          
          MessagePullPolicy pullPolicy = new DefaultMessagePullPolicy();
          

Modified: trunk/src/main/org/jboss/messaging/core/plugin/DefaultPostOfficeService.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/DefaultPostOfficeService.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/DefaultPostOfficeService.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -126,7 +126,7 @@
          
          TransactionRepository tr = serverPeer.getTxRepository();
          
-         String nodeId = serverPeer.getServerPeerID();
+         int nodeId = serverPeer.getServerPeerID();
          
          FilterFactory ff = new SelectorFactory();
                

Modified: trunk/src/main/org/jboss/messaging/core/plugin/JDBCPersistenceManager.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/JDBCPersistenceManager.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/JDBCPersistenceManager.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -1418,6 +1418,8 @@
       {         
          //No tx so we remove the reference directly from the db
          
+         log.info("Removing ref: " + ref);
+         
          TransactionWrapper wrap = new TransactionWrapper();
          
          PreparedStatement psReference = null;
@@ -1909,6 +1911,8 @@
             
             removeReference(pair.channelId, pair.ref, psReference);
             
+            log.info("Removing ref " + pair.ref + " in tx");
+            
             if (batch)
             {
                psReference.addBatch();

Modified: trunk/src/main/org/jboss/messaging/core/plugin/JDBCShutdownLogger.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/JDBCShutdownLogger.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/JDBCShutdownLogger.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -58,7 +58,7 @@
    
    // ShutdownLogger implementation ---------------------------------------------
    
-   public boolean shutdown(String nodeId) throws Exception
+   public boolean shutdown(int nodeId) throws Exception
    {
       boolean exists = existsStartup(nodeId);
       
@@ -76,7 +76,7 @@
       }      
    }
 
-   public boolean startup(String nodeId) throws Exception
+   public boolean startup(int nodeId) throws Exception
    {
       boolean crashed = existsStartup(nodeId);
       
@@ -97,7 +97,7 @@
       return crashed;
    }
    
-   private boolean existsStartup(String nodeId) throws Exception
+   private boolean existsStartup(int nodeId) throws Exception
    {
       Connection conn = null;
       PreparedStatement ps = null;
@@ -108,7 +108,7 @@
       {
          conn = ds.getConnection();
          ps = conn.prepareStatement(getSQLStatement("SELECT_STARTUP"));
-         ps.setString(1, nodeId);
+         ps.setInt(1, nodeId);
          
          rs = ps.executeQuery();
          
@@ -156,7 +156,7 @@
       }
    }
    
-   private void removeStartup(String nodeId) throws Exception
+   private void removeStartup(int nodeId) throws Exception
    {
       Connection conn = null;
       PreparedStatement ps = null;
@@ -166,7 +166,7 @@
       {
          conn = ds.getConnection();
          ps = conn.prepareStatement(getSQLStatement("DELETE_STARTUP"));
-         ps.setString(1, nodeId);
+         ps.setInt(1, nodeId);
          
          ps.executeUpdate();
         
@@ -204,7 +204,7 @@
    
    // Private ------------------------------------------------------------
    
-   private void insertStartup(String nodeId) throws Exception
+   private void insertStartup(int nodeId) throws Exception
    {
       Connection conn = null;
       PreparedStatement ps = null;
@@ -214,7 +214,7 @@
       {
          conn = ds.getConnection();
          ps = conn.prepareStatement(getSQLStatement("INSERT_STARTUP"));
-         ps.setString(1, nodeId);
+         ps.setInt(1, nodeId);
          
          ps.executeUpdate();
         
@@ -254,7 +254,7 @@
    {
       Map sql = new LinkedHashMap();
       
-      sql.put("CREATE_STARTUP", "CREATE TABLE JMS_STARTUP (NODE_ID VARCHAR(255) PRIMARY KEY)");
+      sql.put("CREATE_STARTUP", "CREATE TABLE JMS_STARTUP (NODE_ID INTEGER PRIMARY KEY)");
       
       return sql;
    }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/contract/ShutdownLogger.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/contract/ShutdownLogger.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/contract/ShutdownLogger.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -32,7 +32,7 @@
  */
 public interface ShutdownLogger extends MessagingComponent
 {
-   boolean startup(String nodeId) throws Exception;
+   boolean startup(int nodeId) throws Exception;
    
-   boolean shutdown(String nodeId) throws Exception;
+   boolean shutdown(int nodeId) throws Exception;
 }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/Binding.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/Binding.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/Binding.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -34,7 +34,7 @@
  */
 public interface Binding
 {
-   public String getNodeId();
+   public int getNodeId();
    
    public String getCondition();
    

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultBinding.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultBinding.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultBinding.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -35,7 +35,7 @@
  */
 public class DefaultBinding implements Binding
 {
-   private String nodeId;
+   private int nodeId;
    
    private String condition;
    
@@ -45,7 +45,7 @@
    {      
    }
 
-   public DefaultBinding(String nodeId, String condition, Queue queue)
+   public DefaultBinding(int nodeId, String condition, Queue queue)
    {
       this.nodeId = nodeId;
       
@@ -54,7 +54,7 @@
       this.queue = queue;
    }
    
-   public String getNodeId()
+   public int getNodeId()
    {
       return nodeId;
    }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultPostOffice.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultPostOffice.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/DefaultPostOffice.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -78,7 +78,7 @@
    
    protected TransactionRepository tr;
    
-   protected String nodeId;
+   protected int nodeId;
    
    //Map <node id, Map < queue name, binding > >
    protected Map nameMaps;
@@ -96,7 +96,7 @@
    
    public DefaultPostOffice(DataSource ds, TransactionManager tm, Properties sqlProperties,
                          boolean createTablesOnStartup,
-                         String nodeId, String officeName, MessageStore ms,
+                         int nodeId, String officeName, MessageStore ms,
                          PersistenceManager pm,
                          TransactionRepository tr, FilterFactory filterFactory,
                          QueuedExecutorPool pool)
@@ -160,7 +160,7 @@
       try
       {         
          //We currently only allow one binding per name per node
-         Map nameMap = (Map)nameMaps.get(this.nodeId);
+         Map nameMap = (Map)nameMaps.get(new Integer(this.nodeId));
          
          Binding binding = null;
          
@@ -261,7 +261,7 @@
       
       try
       {
-         Map nameMap = (Map)nameMaps.get(this.nodeId);
+         Map nameMap = (Map)nameMaps.get(new Integer(this.nodeId));
          
          Binding binding = null;
          
@@ -333,7 +333,7 @@
                Binding binding = (Binding)iter.next();
                
                //Sanity check
-               if (!binding.getNodeId().equals(this.nodeId))
+               if (binding.getNodeId() != this.nodeId)
                {
                   throw new IllegalStateException("Local post office has foreign bindings!");
                }
@@ -393,7 +393,7 @@
               
          while (rs.next())
          {
-            String nodeId = rs.getString(1);
+            int nodeId = rs.getInt(1);
             
             String queueName = rs.getString(2);
             
@@ -434,13 +434,13 @@
       }
    }
    
-   protected Binding createBinding(String nodeId, String condition, String queueName, long channelId, String filterString, boolean durable) throws Exception
+   protected Binding createBinding(int nodeId, String condition, String queueName, long channelId, String filterString, boolean durable) throws Exception
    {      
       
       Filter filter = filterFactory.createFilter(filterString);
       
       Queue queue;
-      if (nodeId.equals(this.nodeId))
+      if (nodeId == this.nodeId)
       {
          QueuedExecutor executor = (QueuedExecutor)pool.get();
          
@@ -472,7 +472,7 @@
          String filterString = binding.getQueue().getFilter() == null ? null : binding.getQueue().getFilter().getFilterString();
                   
          ps.setString(1, this.officeName);
-         ps.setString(2, this.nodeId);
+         ps.setInt(2, this.nodeId);
          ps.setString(3, binding.getQueue().getName());
          ps.setString(4, binding.getCondition());         
          if (filterString != null)
@@ -514,7 +514,7 @@
          ps = conn.prepareStatement(getSQLStatement("DELETE_BINDING"));
          
          ps.setString(1, this.officeName);
-         ps.setString(2, this.nodeId);
+         ps.setInt(2, this.nodeId);
          ps.setString(3, queueName);
 
          int rows = ps.executeUpdate();
@@ -542,7 +542,7 @@
       addToConditionMap(binding);
    }   
    
-   protected Binding removeBinding(String nodeId, String queueName)
+   protected Binding removeBinding(int nodeId, String queueName)
    {
       Binding binding = removeFromNameMap(nodeId, queueName);
                   
@@ -553,13 +553,13 @@
    
    protected void addToNameMap(Binding binding)
    {
-      Map nameMap = (Map)nameMaps.get(binding.getNodeId());
+      Map nameMap = (Map)nameMaps.get(new Integer(binding.getNodeId()));
       
       if (nameMap == null)
       {
          nameMap = new LinkedHashMap();
          
-         nameMaps.put(binding.getNodeId(), nameMap);
+         nameMaps.put(new Integer(binding.getNodeId()), nameMap);
       }
       
       nameMap.put(binding.getQueue().getName(), binding);
@@ -581,14 +581,14 @@
       bindings.addBinding(binding);
    }
    
-   protected Binding removeFromNameMap(String nodeId, String queueName)
+   protected Binding removeFromNameMap(int nodeId, String queueName)
    {
       if (queueName == null)
       {
          throw new IllegalArgumentException("Queue name is null");
       }
              
-      Map nameMap = (Map)nameMaps.get(nodeId);
+      Map nameMap = (Map)nameMaps.get(new Integer(nodeId));
       
       if (nameMap == null)
       {
@@ -609,7 +609,7 @@
               
       if (nameMap.isEmpty())
       {
-         nameMaps.remove(nodeId);
+         nameMaps.remove(new Integer(nodeId));
       }
       
       return binding;
@@ -655,7 +655,7 @@
    {
       Map map = new LinkedHashMap();
       map.put("CREATE_POSTOFFICE_TABLE",
-              "CREATE TABLE JMS_POSTOFFICE (POSTOFFICE_NAME VARCHAR(255), NODE_ID VARCHAR(255)," +
+              "CREATE TABLE JMS_POSTOFFICE (POSTOFFICE_NAME VARCHAR(255), NODE_ID INTEGER," +
               "QUEUE_NAME VARCHAR(1023), CONDITION VARCHAR(1023), " +
               "SELECTOR VARCHAR(1023), CHANNEL_ID BIGINT)");
       return map;

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/BindRequest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/BindRequest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/BindRequest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -43,7 +43,7 @@
    {      
    }
    
-   BindRequest(String nodeId, String queueName, String condition, String filterString,
+   BindRequest(int nodeId, String queueName, String condition, String filterString,
                long channelId, boolean durable)
    {
       bindingInfo = new BindingInfo(nodeId, queueName, condition, filterString,

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/BindingInfo.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/BindingInfo.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/BindingInfo.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -38,7 +38,7 @@
  */
 class BindingInfo implements Streamable
 {
-   private String nodeId;   
+   private int nodeId;   
    
    private String queueName;   
    
@@ -54,7 +54,7 @@
    {      
    }
    
-   BindingInfo(String nodeId, String queueName, String condition, String filterString,
+   BindingInfo(int nodeId, String queueName, String condition, String filterString,
                long channelId, boolean durable)
    {
       this.nodeId = nodeId;
@@ -79,7 +79,7 @@
    
    public void read(DataInputStream in) throws Exception
    {
-      nodeId = in.readUTF();
+      nodeId = in.readInt();
       
       queueName = in.readUTF();
       
@@ -94,7 +94,7 @@
 
    public void write(DataOutputStream out) throws Exception
    {
-      out.writeUTF(nodeId);
+      out.writeInt(nodeId);
       
       out.writeUTF(queueName);
       
@@ -127,7 +127,7 @@
       return filterString;
    }
 
-   String getNodeId()
+   int getNodeId()
    {
       return nodeId;
    }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/CastMessagesCallback.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/CastMessagesCallback.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/CastMessagesCallback.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -67,7 +67,7 @@
    
    private List nonPersistent;
    
-   private String nodeId;
+   private int nodeId;
    
    private long txId;
    
@@ -75,7 +75,7 @@
    
    private boolean multicast;
    
-   private String toNodeId;
+   private int toNodeId;
       
    /*
     * We store the id of one of the channels that the ref was inserted into
@@ -85,17 +85,17 @@
    private long checkChannelID;
    
    void addMessage(String routingKey, Message message, Map queueNameToNodeIdMap,
-                   String lastNodeId, long channelID)
+                   int lastNodeId, long channelID)
    {
       //If we only ever send messages to the same node for this tx, then we can unicast rather than multicast
       //This is how we determine that
-      if (lastNodeId == null)
+      if (lastNodeId == -1)
       {
          multicast = true;
       }
       else
       {
-         if (!lastNodeId.equals(toNodeId))
+         if (lastNodeId != toNodeId)
          {
             multicast = true;
          }
@@ -127,7 +127,7 @@
       }
    }
    
-   CastMessagesCallback(String nodeId, long txId, PostOfficeInternal office)
+   CastMessagesCallback(int nodeId, long txId, PostOfficeInternal office)
    {
       this.nodeId = nodeId;
       

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/CheckRequest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/CheckRequest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/CheckRequest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -37,7 +37,7 @@
  */
 class CheckRequest extends ClusterRequest
 {
-   private String nodeId;
+   private int nodeId;
    
    static final int TYPE = 2;
    
@@ -45,7 +45,7 @@
    {      
    }
    
-   CheckRequest(String nodeId)
+   CheckRequest(int nodeId)
    {
       this.nodeId = nodeId;
    }
@@ -63,11 +63,11 @@
    
    public void read(DataInputStream in) throws IOException
    {
-      nodeId = in.readUTF();
+      nodeId = in.readInt();
    }
 
    public void write(DataOutputStream out) throws IOException
    {
-      out.writeUTF(nodeId);      
+      out.writeInt(nodeId);      
    }
 }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/ClusteredQueue.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/ClusteredQueue.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/ClusteredQueue.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -37,7 +37,7 @@
 {
    QueueStats getStats();
    
-   String getNodeId();
+   int getNodeId();
    
    boolean isLocal();
 }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultClusteredBindings.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultClusteredBindings.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultClusteredBindings.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -44,11 +44,11 @@
    // Map <name, router>
    private Map nameMap;
    
-   private String thisNode;
+   private int thisNode;
    
    private int localDurableCount;
    
-   DefaultClusteredBindings(String thisNode)
+   DefaultClusteredBindings(int thisNode)
    {
       super();
       
@@ -61,7 +61,7 @@
    {
       super.addBinding(binding);
   
-      if (binding.getNodeId().equals(thisNode) && binding.getQueue().isRecoverable())
+      if (binding.getNodeId() == thisNode && binding.getQueue().isRecoverable())
       {
          localDurableCount++;
       }      
@@ -76,7 +76,7 @@
          return false;
       }
            
-      if (binding.getNodeId().equals(thisNode) && binding.getQueue().isRecoverable())
+      if (binding.getNodeId() == thisNode && binding.getQueue().isRecoverable())
       {
          localDurableCount--;
       }      

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultClusteredPostOffice.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultClusteredPostOffice.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultClusteredPostOffice.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -149,7 +149,7 @@
     */
    public DefaultClusteredPostOffice(DataSource ds, TransactionManager tm, Properties sqlProperties,
             boolean createTablesOnStartup,
-            String nodeId, String officeName, MessageStore ms,
+            int nodeId, String officeName, MessageStore ms,
             PersistenceManager pm,
             TransactionRepository tr,
             FilterFactory filterFactory,
@@ -176,7 +176,7 @@
     */
    public DefaultClusteredPostOffice(DataSource ds, TransactionManager tm, Properties sqlProperties,
                               boolean createTablesOnStartup,
-                              String nodeId, String officeName, MessageStore ms,
+                              int nodeId, String officeName, MessageStore ms,
                               PersistenceManager pm,
                               TransactionRepository tr,
                               FilterFactory filterFactory,
@@ -200,7 +200,7 @@
    
    private DefaultClusteredPostOffice(DataSource ds, TransactionManager tm, Properties sqlProperties,
                                boolean createTablesOnStartup,
-                               String nodeId, String officeName, MessageStore ms,
+                               int nodeId, String officeName, MessageStore ms,
                                PersistenceManager pm,                               
                                TransactionRepository tr,
                                FilterFactory filterFactory,
@@ -309,7 +309,7 @@
    {           
       log.info(this.nodeId + " binding clustered queue: " + queue + " with condition: " + condition);
       
-      if (!queue.getNodeId().equals(this.nodeId))
+      if (queue.getNodeId() != this.nodeId)
       {
          throw new IllegalArgumentException("Queue node id does not match office node id");
       }
@@ -369,7 +369,7 @@
          
          boolean startInternalTx = false;
          
-         String lastNodeId = null;
+         int lastNodeId = -1;
          
          if (cb != null)
          {
@@ -425,7 +425,7 @@
                         queueNameNodeIdMap = new HashMap();
                      }
                      
-                     queueNameNodeIdMap.put(queue.getName(), queue.getNodeId());
+                     queueNameNodeIdMap.put(queue.getName(), new Integer(queue.getNodeId()));
                   }
                   
                   if (!queue.isLocal())
@@ -488,7 +488,7 @@
                   }
                       
                   callback.addMessage(condition, ref.getMessage(), queueNameNodeIdMap,
-                                      numberRemote == 1 ? lastNodeId : null,
+                                      numberRemote == 1 ? lastNodeId : -1,
                                       lastChannelId);    
                }
             }
@@ -517,7 +517,7 @@
    /*
     * Called when another node adds a binding
     */
-   public void addBindingFromCluster(String nodeId, String queueName, String condition,
+   public void addBindingFromCluster(int nodeId, String queueName, String condition,
                                      String filterString, long channelID, boolean durable)
       throws Exception
    {
@@ -529,13 +529,13 @@
       {                     
          //Sanity
 
-         if (!nodeIdAddressMap.containsKey(nodeId))
+         if (!nodeIdAddressMap.containsKey(new Integer(nodeId)))
          {
             throw new IllegalStateException("Cannot find address for node: " + nodeId);
          }
          
          // We currently only allow one binding per name per node
-         Map nameMap = (Map)nameMaps.get(nodeId);
+         Map nameMap = (Map)nameMaps.get(new Integer(nodeId));
          
          Binding binding = null;
          
@@ -562,14 +562,14 @@
    /*
     * Called when another node removes a binding
     */
-   public void removeBindingFromCluster(String nodeId, String queueName) throws Exception
+   public void removeBindingFromCluster(int nodeId, String queueName) throws Exception
    {
       lock.writeLock().acquire();
       
       try
       {         
          // Sanity
-         if (!nodeIdAddressMap.containsKey(nodeId))
+         if (!nodeIdAddressMap.containsKey(new Integer(nodeId)))
          {
             throw new IllegalStateException("Cannot find address for node: " + nodeId);
          }
@@ -582,13 +582,13 @@
       }
    }
    
-   public void handleAddressNodeMapping(Address address, String nodeId) throws Exception
+   public void handleAddressNodeMapping(Address address, int nodeId) throws Exception
    {
       lock.writeLock().acquire();
       
       try
       { 
-         nodeIdAddressMap.put(nodeId, address);
+         nodeIdAddressMap.put(new Integer(nodeId), address);
       }
       finally
       {
@@ -629,20 +629,20 @@
             {
                Binding binding = (Binding)iter.next();
                                                      
-               if (binding.getNodeId().equals(this.nodeId))
+               if (binding.getNodeId() == this.nodeId)
                {  
                   boolean handle = true;
                   
                   if (queueNameNodeIdMap != null)
-                  {                     
-                     String desiredNodeId = (String)queueNameNodeIdMap.get(binding.getQueue().getName());
+                  {           
+                     Integer in = (Integer)queueNameNodeIdMap.get(binding.getQueue().getName());
                      
                      //When there are more than one queues with the same name across the cluster we only
                      //want to chose one of them
                      
-                     if (desiredNodeId != null)
+                     if (in != null)
                      {
-                        handle = desiredNodeId.equals(nodeId);
+                        handle = in.intValue() == nodeId;
                      }
                   }
                   
@@ -681,7 +681,7 @@
    /*
     * Unicast a message to one members of the group
     */
-   public void asyncSendRequest(ClusterRequest request, String nodeId) throws Exception
+   public void asyncSendRequest(ClusterRequest request, int nodeId) throws Exception
    {               
       Address address = this.getAddressForNodeId(nodeId);
       
@@ -700,7 +700,7 @@
    /*
     * Unicast a sync request
     */
-   public Object syncSendRequest(ClusterRequest request, String nodeId, boolean ignoreNoAddress) throws Exception
+   public Object syncSendRequest(ClusterRequest request, int nodeId, boolean ignoreNoAddress) throws Exception
    {              
       Address address = this.getAddressForNodeId(nodeId);
       
@@ -756,7 +756,7 @@
    /**
     * Check for any transactions that need to be committed or rolled back
     */
-   public void check(String nodeId) throws Throwable
+   public void check(int nodeId) throws Throwable
    {
       synchronized (holdingArea)
       {
@@ -770,7 +770,7 @@
             
             TransactionId id = (TransactionId)entry.getKey();
             
-            if (id.getNodeId().equals(nodeId))
+            if (id.getNodeId() == nodeId)
             {
                ClusterTransaction tx = (ClusterTransaction)iter.next();
                
@@ -815,7 +815,7 @@
       
       try
       {         
-         Map nameMap = (Map)nameMaps.get(nodeId);
+         Map nameMap = (Map)nameMaps.get(new Integer(nodeId));
          
          if (nameMap != null)
          {            
@@ -865,19 +865,19 @@
       }
    }
    
-   public void updateQueueStats(String nodeId, List statsList) throws Exception
+   public void updateQueueStats(int nodeId, List statsList) throws Exception
    {
       lock.readLock().acquire();
       
       try
       {      
-         if (nodeId.equals(this.nodeId))
+         if (nodeId == this.nodeId)
          {
             //Sanity check
             throw new IllegalStateException("Cannot update queue stats for current node");
          }
          
-         Map nameMap = (Map)nameMaps.get(nodeId);
+         Map nameMap = (Map)nameMaps.get(new Integer(nodeId));
          
          if (nameMap == null)
          {
@@ -949,13 +949,13 @@
       return dels;
    }
    
-   public Address getAddressForNodeId(String nodeId) throws Exception
+   public Address getAddressForNodeId(int nodeId) throws Exception
    {
       lock.readLock().acquire();
       
       try
       {
-         return (Address)nodeIdAddressMap.get(nodeId);
+         return (Address)nodeIdAddressMap.get(new Integer(nodeId));
       }
       finally
       {
@@ -1075,14 +1075,14 @@
       }
    }
    
-   protected Binding createBinding(String nodeId, String condition, String queueName, long channelId, String filterString, boolean durable) throws Exception
+   protected Binding createBinding(int nodeId, String condition, String queueName, long channelId, String filterString, boolean durable) throws Exception
    {            
       Filter filter = filterFactory.createFilter(filterString);
       
       log.info("Created binding");
       
       Queue queue;
-      if (nodeId.equals(this.nodeId))
+      if (nodeId == this.nodeId)
       {
          QueuedExecutor executor = (QueuedExecutor)pool.get();
          
@@ -1132,7 +1132,7 @@
       { 
          Iterator iter = nodeIdAddressMap.entrySet().iterator();
          
-         String nodeId = null;
+         Integer nodeId = null;
          while (iter.hasNext())
          {
             Map.Entry entry = (Map.Entry)iter.next();
@@ -1141,7 +1141,7 @@
             
             if (adr.equals(address))
             {
-               nodeId = (String)entry.getKey();
+               nodeId = (Integer)entry.getKey();
             }
          }
          
@@ -1176,7 +1176,7 @@
             {
                Binding binding = (Binding)iter.next();
                
-               removeBinding(nodeId, binding.getQueue().getName());
+               removeBinding(nodeId.intValue(), binding.getQueue().getName());
             }
          }
          
@@ -1245,7 +1245,7 @@
          
          Binding binding = this.createBinding(info.getNodeId(), info.getCondition(), info.getQueueName(), info.getChannelId(), info.getFilterString(), info.isDurable());
          
-         if (binding.getNodeId().equals(this.nodeId))
+         if (binding.getNodeId() == this.nodeId)
          {
             //We deactivate if this is one of our own bindings - it can only
             //be one of our own durable bindings - and since state is retrieved before we are fully started

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultRouter.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultRouter.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/DefaultRouter.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -153,6 +153,8 @@
          //match - in which case it won't match at any other nodes too so no point
          //in trying them
          
+         log.info("sending to local queue");
+         
          Delivery del = localQueue.handle(observer, reference, tx);
          
          return del;
@@ -161,6 +163,8 @@
       {
          //There is no local shared queue
          
+         log.info("There is no local queue");
+         
          //We round robin among the rest
          if (!queues.isEmpty())
          {

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/LocalClusteredQueue.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/LocalClusteredQueue.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/LocalClusteredQueue.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -64,7 +64,7 @@
    
    private RemoteQueueStub pullQueue;
    
-   private String nodeId;
+   private int nodeId;
    
    //TODO Make configurable
    private int pullSize;
@@ -74,7 +74,7 @@
    private Object pullLock = new Object();
  
    //TODO - we shouldn't have to specify office AND nodeId
-   public LocalClusteredQueue(PostOffice office, String nodeId, String name, long id, MessageStore ms, PersistenceManager pm,             
+   public LocalClusteredQueue(PostOffice office, int nodeId, String name, long id, MessageStore ms, PersistenceManager pm,             
                               boolean acceptReliableMessages, boolean recoverable, QueuedExecutor executor,
                               Filter filter, TransactionRepository tr,
                               int fullSize, int pageSize, int downCacheSize)
@@ -89,7 +89,7 @@
       this.office = (PostOfficeInternal)office;
    }
    
-   public LocalClusteredQueue(PostOffice office, String nodeId, String name, long id, MessageStore ms, PersistenceManager pm,             
+   public LocalClusteredQueue(PostOffice office, int nodeId, String name, long id, MessageStore ms, PersistenceManager pm,             
                               boolean acceptReliableMessages, boolean recoverable, QueuedExecutor executor,
                               Filter filter, TransactionRepository tr)
    {
@@ -142,7 +142,7 @@
       return true;
    }
      
-   public String getNodeId()
+   public int getNodeId()
    {
       return nodeId;
    }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/PostOfficeInternal.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/PostOfficeInternal.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/PostOfficeInternal.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -43,14 +43,14 @@
  */
 interface PostOfficeInternal extends ClusteredPostOffice
 {
-   void addBindingFromCluster(String nodeId, String queueName, String condition,
+   void addBindingFromCluster(int nodeId, String queueName, String condition,
                               String filterString, long channelId, boolean durable)
       throws Exception;
    
-   void removeBindingFromCluster(String nodeId, String queueName)
+   void removeBindingFromCluster(int nodeId, String queueName)
       throws Exception;
    
-   void handleAddressNodeMapping(Address address, String nodeId)
+   void handleAddressNodeMapping(Address address, int nodeId)
       throws Exception;
    
    void routeFromCluster(Message message, String routingKey, Map queueNameNodeIdMap) throws Exception;
@@ -59,17 +59,17 @@
    
    void asyncSendRequest(ClusterRequest request) throws Exception;
    
-   void asyncSendRequest(ClusterRequest request, String nodeId) throws Exception;
+   void asyncSendRequest(ClusterRequest request, int nodeId) throws Exception;
    
-   Object syncSendRequest(ClusterRequest request, String nodeId, boolean ignoreNoAddress) throws Exception;
+   Object syncSendRequest(ClusterRequest request, int nodeId, boolean ignoreNoAddress) throws Exception;
    
    void holdTransaction(TransactionId id, ClusterTransaction tx) throws Throwable;
    
    void commitTransaction(TransactionId id) throws Throwable;
    
-   void check(String nodeId) throws Throwable;
+   void check(int nodeId) throws Throwable;
    
-   void updateQueueStats(String nodeId, List stats) throws Exception;
+   void updateQueueStats(int nodeId, List stats) throws Exception;
    
    void sendQueueStats() throws Exception;
    

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/PullMessagesRequest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/PullMessagesRequest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/PullMessagesRequest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -56,7 +56,7 @@
    {      
    }
         
-   PullMessagesRequest(String nodeId, long txId, long checkChannelID, String queueName, int numMessages)
+   PullMessagesRequest(int nodeId, long txId, long checkChannelID, String queueName, int numMessages)
    {
       super(nodeId, txId, true, checkChannelID);
       
@@ -65,7 +65,7 @@
       this.numMessages = numMessages;
    }
    
-   PullMessagesRequest(String nodeId, long txId)
+   PullMessagesRequest(int nodeId, long txId)
    {
       super(nodeId, txId, false);
    }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/QueueStatsRequest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/QueueStatsRequest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/QueueStatsRequest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -41,7 +41,7 @@
 {
    static final int TYPE = 6;
    
-   private String nodeId;
+   private int nodeId;
    
    private List queueStats;
    
@@ -49,7 +49,7 @@
    {      
    }
    
-   QueueStatsRequest(String nodeId, List stats)
+   QueueStatsRequest(int nodeId, List stats)
    {
       this.nodeId = nodeId;
       
@@ -71,7 +71,7 @@
 
    public void read(DataInputStream in) throws Exception
    {
-      nodeId = in.readUTF();
+      nodeId = in.readInt();
       
       int size = in.readInt();
       
@@ -89,7 +89,7 @@
 
    public void write(DataOutputStream out) throws Exception
    {
-      out.writeUTF(nodeId);
+      out.writeInt(nodeId);
       
       out.writeInt(queueStats.size());
       

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/RemoteQueueStub.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/RemoteQueueStub.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/RemoteQueueStub.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -51,7 +51,7 @@
 {
    private static final Logger log = Logger.getLogger(RemoteQueueStub.class);
       
-   private String nodeId;
+   private int nodeId;
    
    private String name;
    
@@ -65,7 +65,7 @@
    
    private QueueStats stats;
    
-   RemoteQueueStub(String nodeId, String name, long id, boolean recoverable, PersistenceManager pm, Filter filter)
+   RemoteQueueStub(int nodeId, String name, long id, boolean recoverable, PersistenceManager pm, Filter filter)
    {
       this.nodeId = nodeId;
       
@@ -80,7 +80,7 @@
       this.filter = filter;
    }
    
-   public String getNodeId()
+   public int getNodeId()
    {
       return nodeId;
    }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/SendNodeIdRequest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/SendNodeIdRequest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/SendNodeIdRequest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -43,13 +43,13 @@
 
    private Address address;
    
-   private String nodeId;
+   private int nodeId;
    
    SendNodeIdRequest()
    {      
    }
    
-   SendNodeIdRequest(Address address, String nodeId)
+   SendNodeIdRequest(Address address, int nodeId)
    {
       this.address = address;
       
@@ -74,7 +74,7 @@
       
       address.readFrom(in);
       
-      nodeId = in.readUTF();
+      nodeId = in.readInt();
    }
 
    public void write(DataOutputStream out) throws Exception
@@ -86,6 +86,6 @@
       
       address.writeTo(out);
       
-      out.writeUTF(nodeId);      
+      out.writeInt(nodeId);   
    }
 }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/SendTransactionRequest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/SendTransactionRequest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/SendTransactionRequest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -50,14 +50,14 @@
    {      
    }
         
-   SendTransactionRequest(String nodeId, long txId, List messageHolders, long channelID)
+   SendTransactionRequest(int nodeId, long txId, List messageHolders, long channelID)
    {
       super(nodeId, txId, true, channelID);
       
       this.messageHolders = messageHolders;  
    }
    
-   SendTransactionRequest(String nodeId, long txId)
+   SendTransactionRequest(int nodeId, long txId)
    {
       super(nodeId, txId, false);
    }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/TransactionId.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/TransactionId.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/TransactionId.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -37,26 +37,24 @@
  */
 class TransactionId implements Streamable
 {
-   private String nodeId;
+   private int nodeId;
    
    private long txId;
    
-   private int hash;
+   private int hash = -1;
    
    TransactionId()
    {      
    }
    
-   TransactionId(String nodeId, long txId)
+   TransactionId(int nodeId, long txId)
    {
       this.nodeId = nodeId;
       
       this.txId = txId;
-      
-      calculateHash();
    }
    
-   String getNodeId()
+   int getNodeId()
    {
       return nodeId;
    }
@@ -68,6 +66,10 @@
    
    public int hashCode()
    {
+      if (hash == -1)
+      {
+         calculateHash();
+      }
       return hash;
    }
    
@@ -85,7 +87,7 @@
       
       TransactionId tother = (TransactionId)other;
       
-      return tother.txId == this.txId && tother.nodeId.equals(this.nodeId);
+      return tother.txId == this.txId && tother.nodeId == this.nodeId;
    }
    
    public String toString()
@@ -99,24 +101,20 @@
       
       hash = 37 * hash + (int)(txId ^ (txId >>> 32));
       
-      hash = 37 * hash + nodeId.hashCode();
+      hash = 37 * hash + nodeId;
    }
 
    public void read(DataInputStream in) throws Exception
    {
-      nodeId = in.readUTF();
+      nodeId = in.readInt();
       
       txId = in.readLong();
-      
-      hash = in.readInt();
    }
 
    public void write(DataOutputStream out) throws Exception
    {
-      out.writeUTF(nodeId);
+      out.writeInt(nodeId);
       
       out.writeLong(txId);
-      
-      out.writeInt(hash);
    }
 }

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/TransactionRequest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/TransactionRequest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/TransactionRequest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -37,7 +37,7 @@
  */
 abstract class TransactionRequest extends ClusterRequest implements ClusterTransaction
 {
-   protected String nodeId;
+   protected int nodeId;
    
    protected long txId;
  
@@ -49,7 +49,7 @@
    {      
    }
       
-   TransactionRequest(String nodeId, long txId, boolean hold, long checkChannelID)
+   TransactionRequest(int nodeId, long txId, boolean hold, long checkChannelID)
    {
       this.nodeId = nodeId;
       
@@ -60,7 +60,7 @@
       this.checkChannelID = checkChannelID;
    }
    
-   TransactionRequest(String nodeId, long txId, boolean hold)
+   TransactionRequest(int nodeId, long txId, boolean hold)
    {
       this.nodeId = nodeId;
       
@@ -86,7 +86,7 @@
    
    public void read(DataInputStream in) throws Exception
    {
-      nodeId = in.readUTF();
+      nodeId = in.readInt();
       
       txId = in.readLong();
       
@@ -95,7 +95,7 @@
 
    public void write(DataOutputStream out) throws Exception
    {
-      out.writeUTF(nodeId);
+      out.writeInt(nodeId);
       
       out.writeLong(txId);
       

Modified: trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/UnbindRequest.java
===================================================================
--- trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/UnbindRequest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/src/main/org/jboss/messaging/core/plugin/postoffice/cluster/UnbindRequest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -37,7 +37,7 @@
 {
    static final int TYPE = 9;
 
-   private String nodeId;   
+   private int nodeId;   
    
    private String queueName;
    
@@ -45,7 +45,7 @@
    {      
    }
 
-   UnbindRequest(String nodeId, String queueName)
+   UnbindRequest(int nodeId, String queueName)
    {
       this.nodeId = nodeId;
       
@@ -66,14 +66,14 @@
 
    public void read(DataInputStream in) throws Exception
    {
-      nodeId = in.readUTF();
+      nodeId = in.readInt();
       
       queueName = in.readUTF();
    }
 
    public void write(DataOutputStream out) throws Exception
    {
-      out.writeUTF(nodeId);
+      out.writeInt(nodeId);
       
       out.writeUTF(queueName);
    }      

Added: trunk/tests/src/org/jboss/test/messaging/core/local/PagingFilteredQueueTestBase.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/core/local/PagingFilteredQueueTestBase.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/tests/src/org/jboss/test/messaging/core/local/PagingFilteredQueueTestBase.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -0,0 +1,6427 @@
+/*
+* 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.core.local;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.jboss.messaging.core.Delivery;
+import org.jboss.messaging.core.Filter;
+import org.jboss.messaging.core.Message;
+import org.jboss.messaging.core.MessageReference;
+import org.jboss.messaging.core.Receiver;
+import org.jboss.messaging.core.local.PagingFilteredQueue;
+import org.jboss.messaging.core.message.CoreMessage;
+import org.jboss.messaging.core.plugin.IdManager;
+import org.jboss.messaging.core.plugin.JDBCPersistenceManager;
+import org.jboss.messaging.core.plugin.SimpleMessageStore;
+import org.jboss.messaging.core.plugin.contract.MessageStore;
+import org.jboss.messaging.core.plugin.contract.PersistenceManager;
+import org.jboss.messaging.core.tx.Transaction;
+import org.jboss.messaging.core.tx.TransactionRepository;
+import org.jboss.test.messaging.MessagingTestCase;
+import org.jboss.test.messaging.core.BrokenReceiver;
+import org.jboss.test.messaging.core.SimpleDeliveryObserver;
+import org.jboss.test.messaging.core.SimpleFilter;
+import org.jboss.test.messaging.core.SimpleReceiver;
+import org.jboss.test.messaging.tools.jmx.ServiceContainer;
+import org.jboss.test.messaging.util.CoreMessageFactory;
+
+import EDU.oswego.cs.dl.util.concurrent.QueuedExecutor;
+
+/**
+ * The QueueTest test strategy is to try as many combination as it makes sense of the following
+ * variables:
+ *
+ * 1. The Queue can be non-recoverable  or
+ *    recoverable. A non-recoverable channel can accept reliable messages or not.
+ * 2. The Queue may have zero or one receivers (the behavior for more than one receiver depends
+ *    on the particular router implementation).
+ * 3. The receiver may be ACKING or NACKING (the case when it throws unchecked exceptions is handled
+ *    at the Router level).
+ * 4. The sender can send message(s) non-transactionally or transactionally (and then can commit
+ *    or rollback the transaction).
+ * 5. The NACKING receiver can send acknowledgment(s) non-transactionally or transactionally (and
+ *    then can commit or rollback the transaction).
+ * 6. The message can be non-reliable or reliable.
+ * 7. The sender can send one or multiple messages.
+ * 8. A recoverable channel may be crashed and tested if it successfully recovers.
+ *
+ * This test base also tests the Distributor interface.
+ *
+ * @author <a href="mailto:ovidiu at jboss.org">Ovidiu Feodorov</a>
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1019 $</tt>
+ *
+ * $Id: ChannelTestBase.java 1019 2006-07-17 17:15:04Z timfox $
+ */
+public abstract class PagingFilteredQueueTestBase extends MessagingTestCase
+{
+   // Constants -----------------------------------------------------
+
+   public static final int NUMBER_OF_MESSAGES = 10;
+
+   // Static --------------------------------------------------------
+   
+   // Attributes ----------------------------------------------------
+
+   protected PersistenceManager pm;
+   
+   protected TransactionRepository tr;
+   
+   protected MessageStore ms;
+   
+   protected ServiceContainer sc;
+
+   protected PagingFilteredQueue queue;
+   
+   // Constructors --------------------------------------------------
+
+   public PagingFilteredQueueTestBase(String name)
+   {
+      super(name);
+   }
+
+   // Public --------------------------------------------------------
+
+   public void setUp() throws Exception
+   {
+      super.setUp();
+      
+      sc = new ServiceContainer("all,-remoting,-security");
+      sc.start();
+
+      pm =
+         new JDBCPersistenceManager(sc.getDataSource(), sc.getTransactionManager(), null,
+                                    true, true, true, 100);      
+      pm.start();
+      
+      tr = new TransactionRepository(pm, new IdManager("TRANSACTION_ID", 10, pm));
+      tr.start();
+      
+      ms = new SimpleMessageStore();
+      ms.start();
+   }
+
+   public void tearDown() throws Exception
+   {
+      sc.stop();
+      sc = null;
+      
+      ms = null;
+      tr = null;
+      super.tearDown();
+   }
+
+   public static void assertEqualSets(MessageReference[] a, List msgs)
+   {
+      assertEquals(a.length, msgs.size());
+      List l = new ArrayList(msgs);
+
+      for(int i = 0; i < a.length; i++)
+      {
+         for(Iterator j = l.iterator(); j.hasNext(); )
+         {
+            Object o = j.next();
+            Message m = (Message)o;
+            
+
+            if (a[i].getMessageID() == m.getMessageID() &&
+                m.getPayload().equals(a[i].getMessage().getPayload()))
+            {
+               j.remove();
+               break;
+            }
+         }
+      }
+
+      if (!l.isEmpty())
+      {
+         fail("Messages " + l + " do not match!");
+      }
+   }
+
+   public static void assertEqualSets(Delivery[] a, List deliveries)
+   {
+      assertEquals(a.length, deliveries.size());
+      List l = new ArrayList(deliveries);
+
+      for(int i = 0; i < a.length; i++)
+      {
+         for(Iterator j = l.iterator(); j.hasNext(); )
+         {
+            Delivery d = (Delivery)j.next();
+            MessageReference ref = d.getReference();
+
+            if (a[i].getReference().getMessageID() == ref.getMessageID())
+            {
+               j.remove();
+               break;
+            }
+         }
+      }
+
+      if (!l.isEmpty())
+      {
+         fail("Deliveries " + l + " do not match!");
+      }
+   }
+
+
+   // Channel tests -------------------------------------------------
+   
+
+   public void testWithFilter()
+   {
+      Filter f = new SimpleFilter(3);
+            
+      PagingFilteredQueue queue = new PagingFilteredQueue("queue1", 1, ms, pm, true, false, new QueuedExecutor(), f);
+      
+      Message m1 = new CoreMessage(1, false, 0, 0, (byte)0, null, null);
+      Message m2 = new CoreMessage(2, false, 0, 0, (byte)0, null, null);
+      Message m3 = new CoreMessage(3, false, 0, 0, (byte)0, null, null);
+      Message m4 = new CoreMessage(4, false, 0, 0, (byte)0, null, null);
+      Message m5 = new CoreMessage(5, false, 0, 0, (byte)0, null, null);
+      
+      MessageReference ref1 = ms.reference(m1);
+      MessageReference ref2 = ms.reference(m2);
+      MessageReference ref3 = ms.reference(m3);
+      MessageReference ref4 = ms.reference(m4);
+      MessageReference ref5 = ms.reference(m5);
+      
+      Delivery del = queue.handle(null, ref1, null);
+      assertFalse(del.isSelectorAccepted());
+      
+      del = queue.handle(null, ref2, null);
+      assertFalse(del.isSelectorAccepted());
+      
+      del = queue.handle(null, ref3, null);
+      assertTrue(del.isSelectorAccepted());
+      
+      del = queue.handle(null, ref4, null);
+      assertFalse(del.isSelectorAccepted());
+      
+      del = queue.handle(null, ref5, null);
+      assertFalse(del.isSelectorAccepted());
+   }
+   
+   
+   public void testUnreliableSynchronousDeliveryTwoReceivers() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+      SimpleReceiver r1 = new SimpleReceiver("ONE", SimpleReceiver.ACKING);
+      SimpleReceiver r2 = new SimpleReceiver("TWO", SimpleReceiver.ACKING);
+      
+      queue.add(r1);
+      queue.add(r2);
+      
+      Delivery d = queue.handle(observer, createReference(0, false, "payload"), null);
+      
+      assertTrue(d.isDone());
+      List l1 = r1.getMessages();
+      List l2 = r2.getMessages();
+      if (l2.isEmpty())
+      {
+         assertEquals(1, l1.size());
+         Message m = (Message)l1.get(0);
+         assertEquals("payload", m.getPayload());
+      }
+      else
+      {
+         assertTrue(l1.isEmpty());
+         assertEquals(1, l2.size());
+         Message m = (Message)l2.get(0);
+         assertEquals("payload", m.getPayload());
+      }
+   }
+
+
+   public void testReliableSynchronousDeliveryTwoReceivers() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+      SimpleReceiver r1 = new SimpleReceiver("ONE", SimpleReceiver.ACKING);
+      SimpleReceiver r2 = new SimpleReceiver("TWO", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r1));
+      assertTrue(queue.add(r2));
+
+      Delivery d = queue.handle(observer, createReference(0, true, "payload"), null);
+
+      assertTrue(d.isDone());
+      List l1 = r1.getMessages();
+      List l2 = r2.getMessages();
+      if (l2.isEmpty())
+      {
+         assertEquals(1, l1.size());
+         Message m = (Message)l1.get(0);
+         assertEquals("payload", m.getPayload());
+      }
+      else
+      {
+         assertTrue(l1.isEmpty());
+         assertEquals(1, l2.size());
+         Message m = (Message)l2.get(0);
+         assertEquals("payload", m.getPayload());
+      }
+   }
+   
+   /*
+    * If a channel has a set a receiver and remove is called with a different receiver
+    * need to ensure the receiver is not removed (since it doesn't match)
+    */
+   public void testRemoveDifferentReceiver() throws Exception
+   {
+      Receiver receiver1 = new SimpleReceiver();
+      
+      Receiver receiver2 = new SimpleReceiver();
+      
+      assertFalse(queue.iterator().hasNext());
+      
+      queue.add(receiver1);
+      
+      assertTrue(queue.contains(receiver1));
+      
+      queue.remove(receiver1);
+      
+      assertFalse(queue.iterator().hasNext());
+      
+      assertFalse(queue.contains(receiver1));
+      
+      queue.add(receiver1);
+      
+      assertTrue(queue.contains(receiver1));
+      
+      queue.remove(receiver2);
+      
+      assertTrue(queue.contains(receiver1));
+                 
+   }
+
+   public void testClosedChannel() throws Exception
+   {
+      queue.close();
+      try
+      {
+         queue.handle(null, createReference(0), null);
+         fail("should throw exception");
+      }
+      catch(IllegalStateException e)
+      {
+         //OK
+      }
+   }
+
+   public void testHandleNullRoutable() throws Exception
+   {
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+      assertNull(queue.handle(observer, null, null));
+   }
+
+   //////////////////////////////////
+   ////////////////////////////////// Test matrix
+   //////////////////////////////////
+
+   //
+   // Non-recoverable channel
+   //
+
+   ////
+   //// Zero receivers
+   ////
+
+   //////
+   ////// Non-transacted send
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      Message sm = (Message)stored.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+
+      SimpleReceiver receiver = new SimpleReceiver("ACKING", SimpleReceiver.ACKING);
+      queue.add(receiver);
+      queue.deliver(true);
+      assertEquals(1, receiver.getMessages().size());
+      assertEquals(0, ((Message)receiver.getMessages().get(0)).getMessageID());
+
+      queue.deliver(true);
+      assertEquals(1, receiver.getMessages().size());
+
+
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // non-transacted send, non-reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      List stored = queue.browse();
+      assertEqualSets(refs, stored);
+
+      SimpleReceiver receiver = new SimpleReceiver("ACKING", SimpleReceiver.ACKING);
+      queue.add(receiver);
+      queue.deliver(true);
+      assertEquals(10, receiver.getMessages().size());
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         assertEquals(i, ((Message)receiver.getMessages().get(i)).getMessageID());         
+      }
+      receiver.clear();
+
+      queue.deliver(true);
+      assertEquals(0, receiver.getMessages().size());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_3_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      // the channel must not accept the message
+      assertNull(delivery);
+
+      assertTrue(queue.browse().isEmpty());
+
+      queue.deliver(true);
+      
+      Receiver r = new SimpleReceiver("ACKING", SimpleReceiver.ACKING);
+      
+      queue.add(r);
+      
+      queue.deliver(true);
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_3_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      Message sm = (Message)stored.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+
+      queue.deliver(true);
+
+      SimpleReceiver receiver = new SimpleReceiver("ACKING", SimpleReceiver.ACKING);
+      queue.add(receiver);
+      queue.deliver(true);
+      assertEquals(1, receiver.getMessages().size());
+      assertEquals(0, ((Message)receiver.getMessages().get(0)).getMessageID());
+
+      queue.deliver(true);
+      assertEquals(1, receiver.getMessages().size());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_4_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         // the channel must not accept the message
+         assertNull(delivery);
+
+         queue.deliver(true);
+         
+         Receiver r = new SimpleReceiver("ACKING", SimpleReceiver.ACKING);
+         
+         queue.add(r);
+         
+         queue.deliver(true);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_4_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+
+      SimpleReceiver receiver = new SimpleReceiver("ACKING", SimpleReceiver.ACKING);
+      queue.add(receiver);
+      queue.deliver(true);
+      assertEquals(10, receiver.getMessages().size());
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         assertEquals(i, ((Message)receiver.getMessages().get(i)).getMessageID());         
+      }
+      receiver.clear();
+
+      queue.deliver(true);
+      assertEquals(0, receiver.getMessages().size());
+   }
+
+
+
+   //////
+   ////// Transacted send and commit
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_5() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      Message sm = (Message)stored.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_6() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      List stored = queue.browse();
+      assertEqualSets(refs, stored);
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_7_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_7_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      Message sm = (Message)stored.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_8_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testNonRecoverableChannel_8_1_mixed() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+   }
+   
+   public void testNonRecoverableChannel_8_1_mixed_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES * 2];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i + NUMBER_OF_MESSAGES] = createReference(i + NUMBER_OF_MESSAGES , true, "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i + NUMBER_OF_MESSAGES], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+   }
+   
+
+   public void testNonRecoverableChannel_8_1_mixed_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES * 2];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i + NUMBER_OF_MESSAGES] = createReference(i + NUMBER_OF_MESSAGES , true, "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i + NUMBER_OF_MESSAGES], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_8_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testNonRecoverableChannel_8_2_mixed() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+   }
+
+
+   //////
+   ////// Transacted send and rollback
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_9() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.rollback();
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_10() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.rollback();
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_11() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.rollback();
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_12() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.rollback();
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testNonRecoverableChannel_12_mixed() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.rollback();
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   ////
+   //// One receiver
+   ////
+
+   //////
+   ////// ACKING receiver
+   //////
+
+   //////
+   ////// Non-transacted send
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_13() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+      assertTrue(queue.browse().isEmpty());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message sm = (Message)received.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_14() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // non-transacted send, non-reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertTrue(queue.browse().isEmpty());
+
+      List received = r.getMessages();
+      assertEqualSets(refs, received);
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_15_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertNull(delivery);
+
+      assertTrue(queue.browse().isEmpty());
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_15_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      assertTrue(queue.browse().isEmpty());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message sm = (Message)received.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_16_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertNull(delivery);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_16_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertTrue(queue.browse().isEmpty());
+      assertEqualSets(refs, r.getMessages());
+   }
+
+   //////
+   ////// Transacted send and commit
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_17() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message sm = (Message)received.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_18() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+      assertEqualSets(refs, r.getMessages());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_19_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_19_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message sm = (Message)received.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_20_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testNonRecoverableChannel_20_1_mixed() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_20_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      assertEqualSets(refs, r.getMessages());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testNonRecoverableChannel_20_2_mixed() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      assertEqualSets(refs, r.getMessages());
+   }
+
+   //////
+   ////// Transacted send and rollback
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_21() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_22() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_23() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_24() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testNonRecoverableChannel_24_mixed() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   //////
+   ////// NACKING receiver
+   //////
+
+   //////
+   ////// Non-transacted send
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   ////////////
+   //////////// Non-transacted acknowledgment
+   ////////////
+
+   public void testNonRecoverableChannel_25() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      // non-transacted acknowledgment
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   /**
+    * The same test as before, but with a Receiver configured to acknowledge immediately
+    * on the Delivery. Simulates a race condition in which the acknoledgment arrives before
+    * the Delivery is returned to channel.
+    *
+    * @throws Throwable
+    */
+   public void testNonRecoverableChannel_25_race() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      r.setImmediateAsynchronousAcknowledgment(true);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      // the receiver should have returned a "done" delivery
+      assertTrue(queue.browse().isEmpty());
+
+      List messages = r.getMessages();
+      assertEquals(1, messages.size());
+      Message ackm = (Message)messages.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      // an extra acknowledgment should be discarded
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   ////////////
+   //////////// Transacted acknowledgment and commit
+   ////////////
+
+   public void testNonRecoverableChannel_25_1() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted acknowledgment
+      r.acknowledge(ackm, tx);
+
+      delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   ////////////
+   //////////// Transacted acknowledgment and rollback
+   ////////////
+
+   public void testNonRecoverableChannel_25_2() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted acknowledgment
+      r.acknowledge(ackm, tx);
+
+      delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      tx.rollback();
+
+      delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      // acknowledge non-transactionally
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   ////////////
+   //////////// Non-transacted acknowledgment
+   ////////////
+
+   public void testNonRecoverableChannel_26() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // non-transacted send, non-reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+
+   }
+
+   ////////////
+   //////////// Transacted acknowledgment and commit
+   ////////////
+
+   public void testNonRecoverableChannel_26_1() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // non-transacted send, non-reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      Transaction tx = tr.createTransaction();
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // transacted acknowledgment
+         r.acknowledge(ackm, tx);
+      }
+
+      assertEqualSets(refs, queue.browse());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   ////////////
+   //////////// Transacted acknowledgment and rollback
+   ////////////
+
+   public void testNonRecoverableChannel_26_2() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // non-transacted send, non-reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      Transaction tx = tr.createTransaction();
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // transacted acknowledgment
+         r.acknowledge(ackm, tx);
+      }
+
+      assertEqualSets(refs, queue.browse());
+
+      tx.rollback();
+
+      assertEqualSets(refs, queue.browse());
+
+      // acknowledge non-transactionally
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   ////////////
+   //////////// Non-transacted acknowledgment
+   ////////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_27_1_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      // not accepted by the channel
+      assertNull(delivery);
+      assertTrue(queue.browse().isEmpty());
+      assertTrue(r.getMessages().isEmpty());
+
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_27_1_2() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+      Message sm = (Message)stored.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message rm = (Message)received.iterator().next();
+      assertTrue(rm.isReliable());
+      assertEquals(0, rm.getMessageID());
+
+      r.acknowledge(rm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   ////////////
+   //////////// Transacted acknowledgment
+   ////////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+
+   // Doesn't make sense, the message won't be accepted anyway.
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+
+   public void testNonRecoverableChannel_27_2_2() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+      Message sm = (Message)stored.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message rm = (Message)received.iterator().next();
+      assertTrue(rm.isReliable());
+      assertEquals(0, rm.getMessageID());
+
+      Transaction tx = tr.createTransaction();
+
+      r.acknowledge(rm, tx);
+
+      stored = queue.browse();
+      assertEquals(1, stored.size());
+      sm = (Message)stored.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   ////////////
+   //////////// Non-transacted acknowledgment
+   ////////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_28_1_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         // not accepted by the channel
+         assertNull(delivery);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_28_1_2() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   ////////////
+   //////////// Transacted acknowledgment
+   ////////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   // Doesn't make sense, the message won't be accepted anyway.
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_28_2_2() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      Transaction tx = tr.createTransaction();
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         r.acknowledge(ackm, tx);
+      }
+
+      assertEqualSets(refs, queue.browse());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   //////
+   ////// Transacted send and commit
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_29() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      // non-transacted acknowledgment
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_30() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_31_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ///////////
+   /////////// Channel does accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_31_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+      Message sm = (Message)stored.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message rm = (Message)received.iterator().next();
+      assertTrue(rm.isReliable());
+      assertEquals(0, rm.getMessageID());
+   }
+
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   ///////////
+   /////////// Channel does NOT accept reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_32_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testNonRecoverableChannel_32_1_mixed() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (queue.acceptReliableMessages())
+      {
+         // we test channels that don't accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      try
+      {
+         tx.commit();
+         fail("this should throw exception");
+      }
+      catch(Exception e)
+      {
+         // OK
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ///////////
+   /////////// Channel accepts reliable messages
+   ///////////
+
+   public void testNonRecoverableChannel_32_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testNonRecoverableChannel_32_2_mixed() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      if (!queue.acceptReliableMessages())
+      {
+         // we test channels that accept reliable messages
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+   }
+
+
+
+   //////
+   ////// Transacted send and rollback
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_33() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_34() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testNonRecoverableChannel_35() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testNonRecoverableChannel_36() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testNonRecoverableChannel_36_mixed() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+
+
+
+   //
+   // Recoverable channel
+   //
+
+   public void testRecoverableChannel_0() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         assertTrue(queue.acceptReliableMessages());
+      }
+   }
+
+   ////
+   //// Zero receivers
+   ////
+
+   //////
+   ////// Non-transacted send
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_1() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      Message sm = (Message)stored.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_2() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // non-transacted send, non-reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_3() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      Message sm = (Message)stored.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_4() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+
+   }
+
+   //////
+   ////// Transacted send and commit
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_5() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      Message sm = (Message)stored.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_6() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_7() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      Message sm = (Message)stored.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_8() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testRecoverableChannel_8_mixed() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+   }
+
+
+   //////
+   ////// Transacted send and rollback
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_9() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.rollback();
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_10() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.rollback();
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_11() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.rollback();
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_12() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.rollback();
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testRecoverableChannel_12_mixed() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      tx.rollback();
+
+      // still no messages in the channel
+      assertEquals(0, queue.browse().size());
+   }
+
+   ////
+   //// One receiver
+   ////
+
+   //////
+   ////// ACKING receiver
+   //////
+
+   //////
+   ////// Non-transacted send
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_13() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+      assertTrue(queue.browse().isEmpty());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message sm = (Message)received.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_14() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // non-transacted send, non-reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertTrue(queue.browse().isEmpty());
+
+      List received = r.getMessages();
+      assertEqualSets(refs, received);
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_15() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      assertTrue(queue.browse().isEmpty());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message sm = (Message)received.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_16() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertTrue(queue.browse().isEmpty());
+      assertEqualSets(refs, r.getMessages());
+   }
+
+   //////
+   ////// Transacted send and commit
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_17() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message sm = (Message)received.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+
+   public void testRecoverableChannel_17_1() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      BrokenReceiver brokenReceiver = new BrokenReceiver(2);
+      assertTrue(queue.add(brokenReceiver));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+
+      log.debug("sending message 1");
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      ref = createReference(1, false, "payload");
+
+      log.debug("sending message 2");
+      queue.handle(observer, ref, tx);
+
+      ref = createReference(2, false, "payload");
+
+      log.debug("sending message 3");
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      tx.commit();
+
+      assertEquals(2, queue.browse().size());
+      assertEquals(1, brokenReceiver.getMessages().size());
+   }
+
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_18() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+      assertEqualSets(refs, r.getMessages());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_19() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      List received = r.getMessages();
+      assertEquals(1, received.size());
+      Message sm = (Message)received.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_20() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      assertEqualSets(refs, r.getMessages());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testRecoverableChannel_20_mixed() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      assertEqualSets(refs, r.getMessages());
+   }
+
+
+   //////
+   ////// Transacted send and rollback
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_21() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_22() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_23() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_24() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testRecoverableChannel_24_mixed() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an ACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("AckingReceiver", SimpleReceiver.ACKING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   //////
+   ////// NACKING receiver
+   //////
+
+   //////
+   ////// Non-transacted send
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   ////////////
+   //////////// Non-transacted acknowledgment
+   ////////////
+
+   public void testRecoverableChannel_25() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      // non-transacted acknowledgment
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   /**
+    * The same test as before, but with a Receiver configured to acknowledge immediately
+    * on the Delivery. Simulates a race condition in which the acknoledgment arrives before
+    * the Delivery is returned to channel.
+    *
+    * @throws Throwable
+    */
+   public void testRecoverableChannel_25_race() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      r.setImmediateAsynchronousAcknowledgment(true);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      // the receiver should have returned a "done" delivery
+      assertTrue(queue.browse().isEmpty());
+
+      List messages = r.getMessages();
+      assertEquals(1, messages.size());
+      Message ackm = (Message)messages.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      // an extra acknowledgment should be discarded
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   ////////////
+   //////////// Transacted acknowledgment and commit
+   ////////////
+
+   public void testRecoverableChannel_25_1() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted acknowledgment
+      r.acknowledge(ackm, tx);
+
+      delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   ////////////
+   //////////// Transacted acknowledgment and rollback
+   ////////////
+
+   public void testRecoverableChannel_25_2() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, non-reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted acknowledgment
+      r.acknowledge(ackm, tx);
+
+      delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      tx.rollback();
+
+      delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      // acknowledge non-transactionally
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   ////////////
+   //////////// Non-transacted acknowledgment
+   ////////////
+
+   public void testRecoverableChannel_26() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // non-transacted send, non-reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+
+   }
+
+   ////////////
+   //////////// Transacted acknowledgment and commit
+   ////////////
+
+   public void testRecoverableChannel_26_1() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // non-transacted send, non-reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      Transaction tx = tr.createTransaction();
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // transacted acknowledgment
+         r.acknowledge(ackm, tx);
+      }
+
+      assertEqualSets(refs, queue.browse());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   ////////////
+   //////////// Transacted acknowledgment and rollback
+   ////////////
+
+   public void testRecoverableChannel_26_2() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // non-transacted send, non-reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      Transaction tx = tr.createTransaction();
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // transacted acknowledgment
+         r.acknowledge(ackm, tx);
+      }
+
+      assertEqualSets(refs, queue.browse());
+
+      tx.rollback();
+
+      assertEqualSets(refs, queue.browse());
+
+      // acknowledge non-transactionally
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   ////////////
+   //////////// Non-transacted acknowledgment
+   ////////////
+
+   public void testRecoverableChannel_27() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      // non-transacted acknowledgment
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   /**
+    * The same test as before, but with a Receiver configured to acknowledge immediately
+    * on the Delivery. Simulates a race condition in which the acknoledgment arrives before
+    * the Delivery is returned to channel.
+    *
+    * @throws Throwable
+    */
+   public void testRecoverableChannel_27_race() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      r.setImmediateAsynchronousAcknowledgment(true);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      // the receiver should have returned a "done" delivery
+      assertTrue(queue.browse().isEmpty());
+
+      List messages = r.getMessages();
+      assertEquals(1, messages.size());
+      Message ackm = (Message)messages.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      // an extra acknowledgment should be discarded
+      
+      //TODO - why should it be discarded?
+      //If you acknowledge twice surely this is a usage error?
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   ////////////
+   //////////// Transacted acknowledgment and commit
+   ////////////
+
+   public void testRecoverableChannel_27_1() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted acknowledgment
+      r.acknowledge(ackm, tx);
+
+      delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   ////////////
+   //////////// Transacted acknowledgment and rollback
+   ////////////
+
+   public void testRecoverableChannel_27_2() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-transacted send, reliable message, one message
+      Delivery delivery = queue.handle(observer, ref, null);
+
+      assertTrue(delivery.isDone());
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted acknowledgment
+      r.acknowledge(ackm, tx);
+
+      delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      tx.rollback();
+
+      delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      // acknowledge non-transactionally
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   ////////////
+   //////////// Non-transacted acknowledgment
+   ////////////
+
+   public void testRecoverableChannel_28() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   ////////////
+   //////////// Transacted acknowledgment and commit
+   ////////////
+
+   public void testRecoverableChannel_28_1() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      Transaction tx = tr.createTransaction();
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // transacted acknowledgment
+         r.acknowledge(ackm, tx);
+      }
+
+      assertEqualSets(refs, queue.browse());
+
+      tx.commit();
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   ////////////
+   //////////// Transacted acknowledgment and rollback
+   ////////////
+
+   public void testRecoverableChannel_28_2() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // non-transacted send, reliable message, multiple messages
+         Delivery delivery = queue.handle(observer, refs[i], null);
+
+         assertTrue(delivery.isDone());
+      }
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      Transaction tx = tr.createTransaction();
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // transacted acknowledgment
+         r.acknowledge(ackm, tx);
+      }
+
+      assertEqualSets(refs, queue.browse());
+
+      tx.rollback();
+
+      assertEqualSets(refs, queue.browse());
+
+      // acknowledge non-transactionally
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   //////
+   ////// Transacted send and commit
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_29() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      // non-transacted acknowledgment
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_30() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_31() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      List delivering = queue.browse();
+      assertEquals(1, delivering.size());
+      assertEquals(0, ((Message)delivering.get(0)).getMessageID());
+
+      List acknowledging = r.getMessages();
+      assertEquals(1, acknowledging.size());
+      Message ackm = (Message)acknowledging.get(0);
+      assertEquals(0, ackm.getMessageID());
+
+      // non-transacted acknowledgment
+      r.acknowledge(ackm, null);
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_32() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel yet
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testRecoverableChannel_32_mixed() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.commit();
+
+      assertEqualSets(refs, queue.browse());
+      assertEqualSets(refs, r.getMessages());
+
+      for(Iterator i = r.getMessages().iterator(); i.hasNext();)
+      {
+         Message ackm = (Message)i.next();
+         // non-transacted acknowledgment
+         r.acknowledge(ackm, null);
+      }
+
+      assertTrue(queue.browse().isEmpty());
+   }
+
+
+   //////
+   ////// Transacted send and rollback
+   //////
+
+   ////////
+   //////// Non-reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_33() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, non-reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_34() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, false, "payload" + i);
+
+         // transacted send, non-reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ////////
+   //////// Reliable message
+   ////////
+
+   //////////
+   ////////// One message
+   //////////
+
+   public void testRecoverableChannel_35() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      // transacted send, reliable message, one message
+      // for a transactional send, handle() return value is unspecified
+      queue.handle(observer, ref, tx);
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   //////////
+   ////////// Multiple message
+   //////////
+
+   public void testRecoverableChannel_36() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         refs[i] = createReference(i, true, "payload" + i);
+
+         // transacted send, reliable message, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   /**
+    * This is a variation where I send a mixture of reliable and non-reliable messages,
+    */
+   public void testRecoverableChannel_36_mixed() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // add an NACKING receiver to the channel
+      SimpleReceiver r = new SimpleReceiver("NackingReceiver", SimpleReceiver.ACCEPTING);
+      assertTrue(queue.add(r));
+
+
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      Transaction tx = tr.createTransaction();
+
+      MessageReference[] refs = new MessageReference[NUMBER_OF_MESSAGES];
+      for(int i = 0; i < NUMBER_OF_MESSAGES; i++)
+      {
+         // send a mixture of reliable and non-reliable messages
+         refs[i] = createReference(i, (i % 2 == 1), "payload" + i);
+
+         // transacted send, reliable/non-reliable messages, multiple messages
+         // for a transactional send, handle() return value is unspecified
+         queue.handle(observer, refs[i], tx);
+      }
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+
+      tx.rollback();
+
+      // no messages in the channel
+      assertEquals(0, queue.browse().size());
+
+      // no message at the receiver
+      assertTrue(r.getMessages().isEmpty());
+   }
+
+   ///////////////////////////////
+   /////////////////////////////// Add receiver tests
+   ///////////////////////////////
+   ///////////////////////////////
+   ///////////////////////////////
+
+   //
+   // Non-recoverable channel
+   //
+
+   ////
+   //// Non-reliable message
+   ////
+
+   //////
+   ////// Broken receiver
+   //////
+
+   public void testAddReceiver_1() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-recoverable channel, non-reliable message
+      Delivery delivery = queue.handle(observer, ref, null);
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+
+      SimpleReceiver receiver = new SimpleReceiver("BrokenReceiver", SimpleReceiver.BROKEN);
+      assertTrue(queue.add(receiver));
+
+      stored = queue.browse();
+      assertEquals(1, stored.size());
+      Message sm = (Message)stored.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+
+      assertTrue(receiver.getMessages().isEmpty());
+   }
+
+   //////
+   ////// ACKING receiver
+   //////
+
+   public void testAddReceiver_2() throws Exception
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-recoverable channel, non-reliable message
+      Delivery delivery = queue.handle(observer, ref, null);
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      SimpleReceiver receiver =
+            new SimpleReceiver("ACKINGReceiver", SimpleReceiver.ACKING, queue);
+      assertTrue(queue.add(receiver));
+
+      assertEquals(1, queue.browse().size());
+
+      // receiver explicitely asks for message
+      receiver.requestMessages();
+
+      assertTrue(queue.browse().isEmpty());
+
+      List messages = receiver.getMessages();
+      assertEquals(1, messages.size());
+      Message sm = (Message)messages.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////
+   ////// NACKING receiver
+   //////
+
+   public void testAddReceiver_3() throws Throwable
+   {
+      if (queue.isRecoverable())
+      {
+         // we test only non-recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, false, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-recoverable channel, non-reliable message
+      Delivery delivery = queue.handle(observer, ref, null);
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      SimpleReceiver receiver =
+            new SimpleReceiver("NACKINGReceiver", SimpleReceiver.ACCEPTING, queue);
+      assertTrue(queue.add(receiver));
+
+      assertEquals(1, queue.browse().size());
+
+      // receiver explicitely asks for message
+      receiver.requestMessages();
+
+      assertEquals(1, queue.browse().size());
+
+      List messages = receiver.getMessages();
+      assertEquals(1, messages.size());
+      Message sm = (Message)messages.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+
+      receiver.acknowledge(sm, null);
+
+      assertTrue(queue.browse().isEmpty());
+
+      messages = receiver.getMessages();
+      assertEquals(1, messages.size());
+      sm = (Message)messages.iterator().next();
+      assertFalse(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //
+   // Recoverable channel
+   //
+
+   ////
+   //// Reliable message
+   ////
+
+   public void testAddReceiver_4() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-recoverable channel, non-reliable message
+      Delivery delivery = queue.handle(observer, ref, null);
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+
+      SimpleReceiver receiver = new SimpleReceiver("BrokenReceiver", SimpleReceiver.BROKEN);
+      assertTrue(queue.add(receiver));
+
+      stored = queue.browse();
+      assertEquals(1, stored.size());
+      Message sm = (Message)stored.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+
+      assertTrue(receiver.getMessages().isEmpty());
+   }
+
+   //////
+   ////// ACKING receiver
+   //////
+
+   public void testAddReceiver_5() throws Exception
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-recoverable channel, non-reliable message
+      Delivery delivery = queue.handle(observer, ref, null);
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      SimpleReceiver receiver =
+            new SimpleReceiver("ACKINGReceiver", SimpleReceiver.ACKING, queue);
+      assertTrue(queue.add(receiver));
+
+      // receiver explicitely asks for message
+      receiver.requestMessages();
+
+      assertTrue(queue.browse().isEmpty());
+
+      List messages = receiver.getMessages();
+      assertEquals(1, messages.size());
+      Message sm = (Message)messages.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+   //////
+   ////// NACKING receiver
+   //////
+
+   public void testAddReceiver_6() throws Throwable
+   {
+      if (!queue.isRecoverable())
+      {
+         // we test only recoverable channels now
+         return;
+      }
+
+      // the channel has no receivers
+      assertFalse(queue.iterator().hasNext());
+
+      MessageReference ref = createReference(0, true, "payload");
+      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+
+      // non-recoverable channel, non-reliable message
+      Delivery delivery = queue.handle(observer, ref, null);
+      assertTrue(delivery.isDone());
+
+      List stored = queue.browse();
+      assertEquals(1, stored.size());
+
+      SimpleReceiver receiver =
+            new SimpleReceiver("NACKINGReceiver", SimpleReceiver.ACCEPTING, queue);
+      assertTrue(queue.add(receiver));
+
+      assertEquals(1, queue.browse().size());
+
+      // receiver explicitely asks for message
+      receiver.requestMessages();
+
+      assertEquals(1, queue.browse().size());
+
+      List messages = receiver.getMessages();
+      assertEquals(1, messages.size());
+      Message sm = (Message)messages.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+
+      receiver.acknowledge(sm, null);
+
+      assertTrue(queue.browse().isEmpty());
+
+      messages = receiver.getMessages();
+      assertEquals(1, messages.size());
+      sm = (Message)messages.iterator().next();
+      assertTrue(sm.isReliable());
+      assertEquals(0, sm.getMessageID());
+   }
+
+
+
+
+   ///////////////////////////////
+   /////////////////////////////// Channel crash tests
+   ///////////////////////////////
+
+//   public void testReliableChannelFailure() throws Throwable
+//   {
+//      if (!channel.isRecoverable())
+//      {
+//         return;
+//      }
+//
+//      SimpleDeliveryObserver observer = new SimpleDeliveryObserver();
+//      SimpleReceiver r = new SimpleReceiver("ONE", SimpleReceiver.NACKING);
+//      channel.add(r);
+//
+//      Routable m = Factory.createMessage("m0", true, "payload");
+//      Delivery d = channel.handle(observer, ref, null);
+//      assertTrue(d.isDone());
+//
+//      List l = r.getMessages();
+//      assertEquals(1, l.size());
+//      Message rm  = (Message)l.get(0);
+//      assertEquals(rm.getMessageID(), m.getMessageID());
+//
+//      crashChannel();
+//
+//      recoverChannel();
+//
+//      // make sure the recovered channel still holds the message
+//
+//      l = channel.browse();
+//      assertEquals(1, l.size());
+//      MessageReference ref = (MessageReference)l.get(0);
+//      rm  = ref.getMessage();
+//      assertEquals(rm.getMessageID(), m.getMessageID());
+//
+//
+//      // TODO review this
+//      try
+//      {
+//         r.acknowledge(m, null);
+//         fail("should throw exception");
+//      }
+//      catch(IllegalStateException e)
+//      {
+//         // OK
+//      }
+//   }
+
+
+   // Distributor tests ---------------------------------------------
+
+   public void testAddOneReceiver()
+   {
+      Receiver r = new SimpleReceiver("ONE");
+
+      assertTrue(queue.add(r));
+      assertFalse(queue.add(r));
+
+      assertTrue(queue.contains(r));
+
+      Iterator i = queue.iterator();
+      assertEquals(r, i.next());
+      assertFalse(i.hasNext());
+
+      queue.clear();
+      assertFalse(queue.iterator().hasNext());
+   }
+
+   public void testRemoveInexistentReceiver()
+   {
+      assertFalse(queue.remove(new SimpleReceiver("INEXISTENT")));
+   }
+
+
+   // Package protected ---------------------------------------------
+   
+   // Protected -----------------------------------------------------
+
+   protected abstract void crashChannel() throws Exception;
+
+   protected abstract void recoverChannel() throws Exception;
+
+   // Private -------------------------------------------------------
+   
+   private MessageReference createReference(long id, boolean reliable, Serializable payload)
+   {
+      return ms.reference(CoreMessageFactory.createCoreMessage(id, reliable, payload));
+   }
+   
+   private MessageReference createReference(long id)
+   {
+      return ms.reference(CoreMessageFactory.createCoreMessage(id));
+   }
+   
+   // Inner classes -------------------------------------------------
+
+}

Added: trunk/tests/src/org/jboss/test/messaging/core/paging/PagingStateTestBase.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/core/paging/PagingStateTestBase.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/tests/src/org/jboss/test/messaging/core/paging/PagingStateTestBase.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -0,0 +1,572 @@
+/*
+  * 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.core.paging;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.naming.InitialContext;
+import javax.sql.DataSource;
+import javax.transaction.TransactionManager;
+
+import org.jboss.messaging.core.Channel;
+import org.jboss.messaging.core.Delivery;
+import org.jboss.messaging.core.DeliveryObserver;
+import org.jboss.messaging.core.MessageReference;
+import org.jboss.messaging.core.Receiver;
+import org.jboss.messaging.core.SimpleDelivery;
+import org.jboss.messaging.core.plugin.IdManager;
+import org.jboss.messaging.core.plugin.JDBCPersistenceManager;
+import org.jboss.messaging.core.plugin.SimpleMessageStore;
+import org.jboss.messaging.core.plugin.contract.PersistenceManager;
+import org.jboss.messaging.core.tx.Transaction;
+import org.jboss.messaging.core.tx.TransactionRepository;
+import org.jboss.messaging.core.tx.XidImpl;
+import org.jboss.test.messaging.MessagingTestCase;
+import org.jboss.test.messaging.tools.jmx.ServiceContainer;
+import org.jboss.tm.TransactionManagerService;
+import org.jboss.util.id.GUID;
+
+/**
+ * 
+ * A PagingStateTestBase.
+ * 
+ * @author <a href="tim.fox at jboss.com">Tim Fox</a>
+ * @version 1.1
+ *
+ * PagingStateTestBase.java,v 1.1 2006/03/22 10:23:35 timfox Exp
+ */
+public class PagingStateTestBase extends MessagingTestCase
+{
+   // Constants -----------------------------------------------------
+
+   // Static --------------------------------------------------------
+         
+   // Attributes ----------------------------------------------------
+
+   protected ServiceContainer sc;
+   protected PersistenceManager pm;
+   protected SimpleMessageStore ms;
+   protected TransactionRepository tr;
+
+   // Constructors --------------------------------------------------
+
+   public PagingStateTestBase(String name)
+   {
+      super(name);
+   }
+
+   // Public --------------------------------------------------------
+   
+   public void testEmpty()
+   {
+      
+   }
+
+   public void setUp() throws Exception
+   {
+      super.setUp();
+
+      sc = new ServiceContainer("all,-remoting,-security");
+      sc.start();
+
+      pm =
+         new JDBCPersistenceManager(sc.getDataSource(), sc.getTransactionManager(), null,
+                                    true, false, true, 100);      
+      pm.start();
+      
+      tr = new TransactionRepository(pm, new IdManager("TRANSACTION_ID", 10, pm));
+      tr.start();
+      
+      ms = new SimpleMessageStore();
+      ms.start();
+   }
+   
+   
+   public void tearDown() throws Exception
+   {
+      pm.stop();
+      tr.stop();
+      ms.stop();
+      sc.stop();
+      
+      super.tearDown();
+   }
+   
+   protected Transaction createXATx() throws Exception
+   {
+      XidImpl xid = new XidImpl(new GUID().toString().getBytes(), 345, new GUID().toString().getBytes());
+      
+      return tr.createTransaction(xid);
+   }
+
+   protected void assertSameIds(List ids, MessageReference[] refs, int start, int end)
+   {
+      assertNotNull(ids);
+      assertEquals(ids.size(), end - start + 1);
+      Iterator iter = ids.iterator();
+      int i = start;
+      while (iter.hasNext())
+      {
+         Long id = (Long)iter.next();
+         assertEquals(refs[i].getMessageID(), id.longValue());
+         i++;
+      }
+   }
+   
+   class ConsumingReceiver implements Receiver
+   {
+      int numToConsume;
+      
+      int count;
+      
+      MessageReference[] refs;
+      
+      int consumeCount;
+      
+      boolean xa;
+      
+      boolean tx;
+      
+      SimpleDelivery[] dels;
+      
+      ConsumingReceiver(int numToConsume, MessageReference[] refs, int consumeCount, boolean tx, boolean xa)
+         throws Exception
+      {
+         this.numToConsume = numToConsume;
+         
+         this.refs = refs;
+         
+         this.consumeCount = consumeCount;
+         
+         this.xa = xa;
+         
+         this.tx = tx;
+         
+         this.dels = new SimpleDelivery[numToConsume];
+      }
+
+      public synchronized Delivery handle(DeliveryObserver observer, MessageReference ref, Transaction tx)
+      {  
+         if (count >= numToConsume)
+         {
+            return null;
+         }
+         
+         assertEquals(refs[consumeCount + count].getMessageID(), ref.getMessageID());
+         
+         SimpleDelivery del = new SimpleDelivery(observer, ref);
+         
+         dels[count] = del;
+         
+         count++;
+         
+         if (count == numToConsume)
+         {
+            notify();
+         }
+           
+         return del;                 
+      }      
+      
+      void acknowledge() throws Throwable
+      {
+         //Wait for them all to arrive first
+         
+         synchronized (this)
+         {
+         
+            while (count < numToConsume)
+            {
+               wait(10000);
+      
+               if (count < numToConsume)
+               {
+                  PagingStateTestBase.fail();
+                  return;
+               }
+            }
+         }
+         
+         Transaction theTx = null;
+         
+         if (tx)
+         {
+            if (xa)
+            {
+               theTx = createXATx();
+            }
+            else
+            {
+               theTx = tr.createTransaction();
+            }
+         }
+         
+         for (int i = 0; i < numToConsume; i++)
+         {
+            dels[i].acknowledge(theTx);
+         }
+         
+         if (tx)
+         {
+            if (xa)
+            {
+               theTx.prepare();
+               theTx.commit();
+            }
+            else
+            {
+               theTx.commit();
+            }
+         }    
+      }
+   }
+   
+   class CancellingReceiver implements Receiver
+   {
+      int numToCancel;
+      
+      int count;
+        
+      SimpleDelivery[] toCancel;
+      
+      CancellingReceiver(int numToConsume)
+         throws Exception
+      {
+         this.numToCancel = numToConsume;
+         
+         this.toCancel = new SimpleDelivery[numToCancel];
+         
+      }
+
+      public synchronized Delivery handle(DeliveryObserver observer, MessageReference ref, Transaction tx)
+      {
+         if (count == numToCancel)
+         {
+            return null;
+         }
+         
+         SimpleDelivery del = new SimpleDelivery(observer, ref);
+         
+         toCancel[count] = del;                  
+         
+         count++;         
+         
+         if (count == numToCancel)
+         {
+            notify();
+         }
+         
+         return del;
+                  
+      }      
+      
+      public synchronized SimpleDelivery[] getToCancel() throws Exception
+      {
+         // Wait for them all to arrive first
+         
+         while (count < numToCancel)
+         {
+            wait(1000);
+            
+            if (count < numToCancel)
+            {
+               PagingStateTestBase.fail();
+               return null;
+            }
+         }
+         
+         return toCancel;
+         
+      }
+      
+      void cancel() throws Exception
+      {
+         //Wait for them all to arrive first
+         
+         synchronized (this)
+         {
+            
+            while (count < numToCancel)
+            {
+               wait(1000);
+               
+               if (count < numToCancel)
+               {
+                  PagingStateTestBase.fail();
+                  return;
+               }
+            }
+         }
+         
+         for (int i = numToCancel - 1; i >=0; i--)
+         {
+            try
+            {
+               toCancel[i].cancel();
+            }
+            catch (Throwable t)
+            {
+               log.error("Failed to cancel", t);
+               PagingStateTestBase.fail();
+            }
+         }
+      }
+   }
+
+   protected void consume(Channel channel, int consumeCount,
+         MessageReference[] refs, int num)
+      throws Throwable
+   {
+      ConsumingReceiver r = new ConsumingReceiver(num, refs, consumeCount, false, false);
+      channel.add(r);
+      channel.deliver(false);
+      r.acknowledge();
+      channel.remove(r);
+      //Need to give enough time for the call to handle to complete and return
+      //thus removing the ref
+      Thread.sleep(500);
+   }
+   
+   protected void consumeInTx(Channel channel, int consumeCount,
+         MessageReference[] refs, int num)
+      throws Throwable
+   {
+      ConsumingReceiver r = new ConsumingReceiver(num, refs, consumeCount, true, false);
+      channel.add(r);
+      channel.deliver(false);
+      r.acknowledge();
+      channel.remove(r);
+      //Need to give enough time for the call to handle to complete and return
+      //thus removing the ref
+      Thread.sleep(500);
+   }
+   
+   protected void consumeIn2PCTx(Channel channel, int consumeCount,
+         MessageReference[] refs, int num)
+      throws Throwable
+   {
+      ConsumingReceiver r = new ConsumingReceiver(num, refs, consumeCount, true, true);
+      channel.add(r);
+      channel.deliver(false);
+      r.acknowledge();
+      channel.remove(r);
+      //Need to give enough time for the call to handle to complete and return
+      //thus removing the ref
+      Thread.sleep(500);
+   }
+   
+   protected SimpleDelivery[] getDeliveries(Channel channel, int number) throws Exception
+   {
+      CancellingReceiver r1 = new CancellingReceiver(number);
+      channel.add(r1);
+      channel.deliver(false);   
+      SimpleDelivery[] dels = r1.getToCancel();
+      channel.remove(r1);
+      //Need to give enough time for the call to handle to complete and return
+      //thus removing the ref
+      Thread.sleep(500);      
+      
+      return dels;
+   }
+   
+   protected void cancelDeliveries(Channel channel, int number) throws Exception
+   {
+      CancellingReceiver r1 = new CancellingReceiver(number);
+      channel.add(r1);
+      channel.deliver(false);   
+      r1.cancel();
+      channel.remove(r1);
+      //Need to give enough time for the call to handle to complete and return
+      //thus removing the ref
+      Thread.sleep(500);      
+   }
+   
+   
+   protected List getReferenceIdsOrderedByOrd(long channelId) throws Exception
+   {
+      InitialContext ctx = new InitialContext();
+
+      TransactionManager mgr = (TransactionManager)ctx.lookup(TransactionManagerService.JNDI_NAME);
+      DataSource ds = (DataSource)ctx.lookup("java:/DefaultDS");
+      
+      javax.transaction.Transaction txOld = mgr.suspend();
+      mgr.begin();
+
+      Connection conn = ds.getConnection();
+      
+      List msgIds = new ArrayList();
+
+      String sql = "SELECT MESSAGEID, ORD, PAGE_ORD FROM JMS_MESSAGE_REFERENCE WHERE CHANNELID=? ORDER BY ORD";
+      PreparedStatement ps = conn.prepareStatement(sql);
+      ps.setLong(1, channelId);
+   
+      ResultSet rs = ps.executeQuery();
+            
+      while (rs.next())
+      {
+         long msgId = rs.getLong(1);
+         long ord = rs.getLong(2);         
+         
+         msgIds.add(new Long(msgId));
+      }
+      rs.close();
+      ps.close();
+       
+      conn.close();
+      
+      mgr.commit();
+
+      if (txOld != null)
+      {
+         mgr.resume(txOld);
+      }
+      
+      return msgIds;
+   }
+   
+   protected List getReferenceIdsOrderedByPageOrd(long channelId) throws Exception
+   {
+      InitialContext ctx = new InitialContext();
+
+      TransactionManager mgr = (TransactionManager)ctx.lookup(TransactionManagerService.JNDI_NAME);
+      DataSource ds = (DataSource)ctx.lookup("java:/DefaultDS");
+      
+      javax.transaction.Transaction txOld = mgr.suspend();
+      mgr.begin();
+
+      Connection conn = ds.getConnection();
+      
+      List msgIds = new ArrayList();
+
+      //log.info("channel id:" + channelId);
+      
+      String sql = "SELECT MESSAGEID, ORD, PAGE_ORD FROM JMS_MESSAGE_REFERENCE WHERE CHANNELID=? ORDER BY PAGE_ORD";
+      PreparedStatement ps = conn.prepareStatement(sql);
+      ps.setLong(1, channelId);
+   
+      ResultSet rs = ps.executeQuery();
+            
+      while (rs.next())
+      {
+         long msgId = rs.getLong(1);     
+         long pageOrd = rs.getLong(3);
+         
+         //log.info("Exists " + msgId + " with page ord " + pageOrd);
+         
+         msgIds.add(new Long(msgId));
+      }
+      rs.close();
+      ps.close();
+       
+      conn.close();
+
+      mgr.commit();
+
+      if (txOld != null)
+      {
+         mgr.resume(txOld);
+      }
+      
+      return msgIds;
+   }
+   
+   protected List getPagedReferenceIds(long channelId) throws Exception
+   {
+      InitialContext ctx = new InitialContext();
+
+      TransactionManager mgr = (TransactionManager)ctx.lookup(TransactionManagerService.JNDI_NAME);
+      DataSource ds = (DataSource)ctx.lookup("java:/DefaultDS");
+      
+      javax.transaction.Transaction txOld = mgr.suspend();
+      mgr.begin();
+
+      Connection conn = ds.getConnection();
+      String sql = "SELECT MESSAGEID FROM JMS_MESSAGE_REFERENCE WHERE CHANNELID=? AND PAGE_ORD IS NOT NULL ORDER BY PAGE_ORD";
+      PreparedStatement ps = conn.prepareStatement(sql);
+      ps.setLong(1, channelId);
+   
+      ResultSet rs = ps.executeQuery();
+      
+      List msgIds = new ArrayList();
+      
+      while (rs.next())
+      {
+         long msgId = rs.getLong(1);
+         msgIds.add(new Long(msgId));
+      }
+      rs.close();
+      ps.close();
+      conn.close();
+
+      mgr.commit();
+
+      if (txOld != null)
+      {
+         mgr.resume(txOld);
+      }
+      
+      return msgIds;
+   }
+   
+   protected List getMessageIds() throws Exception
+   {
+      InitialContext ctx = new InitialContext();
+
+      TransactionManager mgr = (TransactionManager)ctx.lookup(TransactionManagerService.JNDI_NAME);
+      DataSource ds = (DataSource)ctx.lookup("java:/DefaultDS");
+      
+      javax.transaction.Transaction txOld = mgr.suspend();
+      mgr.begin();
+
+      Connection conn = ds.getConnection();
+      String sql = "SELECT MESSAGEID FROM JMS_MESSAGE ORDER BY MESSAGEID";
+      PreparedStatement ps = conn.prepareStatement(sql);
+      
+      ResultSet rs = ps.executeQuery();
+      
+      List msgIds = new ArrayList();
+      
+      while (rs.next())
+      {
+         long msgId = rs.getLong(1);
+         msgIds.add(new Long(msgId));
+      }
+      rs.close();
+      ps.close();
+      conn.close();
+
+      mgr.commit();
+
+      if (txOld != null)
+      {
+         mgr.resume(txOld);
+      }
+      
+      return msgIds;
+   }
+   
+}

Modified: trunk/tests/src/org/jboss/test/messaging/core/plugin/base/ClusteringTestBase.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/core/plugin/base/ClusteringTestBase.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/tests/src/org/jboss/test/messaging/core/plugin/base/ClusteringTestBase.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -140,7 +140,7 @@
       
       DefaultPostOffice postOffice = 
          new DefaultPostOffice(sc.getDataSource(), sc.getTransactionManager(),
-                            null, true, "node1", "Simple", ms, pm, tr, ff, pool);
+                            null, true, 1, "Simple", ms, pm, tr, ff, pool);
       
       postOffice.start();      
       

Modified: trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultClusteredPostOfficeTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultClusteredPostOfficeTest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultClusteredPostOfficeTest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -96,22 +96,22 @@
       {         
          //Start one office
          
-         office1 = createClusteredPostOffice("node1", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
          
          //Add a couple of bindings
          
-         LocalClusteredQueue queue1 = new LocalClusteredQueue(office1, "node1", "sub1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue1 = new LocalClusteredQueue(office1, 1, "sub1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          
          Binding binding1 =
             office1.bindClusteredQueue("topic1", queue1);
-         LocalClusteredQueue queue2 = new LocalClusteredQueue(office1, "node1", "sub2", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue2 = new LocalClusteredQueue(office1, 1, "sub2", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
 
          Binding binding2 =
             office1.bindClusteredQueue("topic1", queue2);
          
          //Start another office - make sure it picks up the bindings from the first node
          
-         office2 = createClusteredPostOffice("node2", "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
          
          Collection bindings = office2.listBindingsForCondition("topic1");
          assertNotNull(bindings);
@@ -123,7 +123,7 @@
          
          //Add another binding on node 2
          
-         LocalClusteredQueue queue3 = new LocalClusteredQueue(office2, "node2", "sub3", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue3 = new LocalClusteredQueue(office2, 2, "sub3", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
 
          Binding binding3 =
             office2.bindClusteredQueue("topic1", queue3);
@@ -150,7 +150,7 @@
 
          //Add another binding on node 1
          
-         LocalClusteredQueue queue4 = new LocalClusteredQueue(office2, "node2", "sub4", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue4 = new LocalClusteredQueue(office2, 2, "sub4", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding4 =
             office2.bindClusteredQueue("topic1", queue4);
          
@@ -200,7 +200,7 @@
          
          //Add a third office
                   
-         office3 = createClusteredPostOffice("node3", "testgroup");
+         office3 = createClusteredPostOffice(3, "testgroup");
          
          //Maks sure it picks up the bindings
          
@@ -214,7 +214,7 @@
          
          //Add another binding on node 3
                   
-         LocalClusteredQueue queue5 = new LocalClusteredQueue(office3, "node3", "sub5", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue5 = new LocalClusteredQueue(office3, 3, "sub5", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          
          Binding binding5 =
             office3.bindClusteredQueue("topic1", queue5);
@@ -250,12 +250,12 @@
          
          //Add a durable and a non durable binding on node 1
          
-         LocalClusteredQueue queue6 = new LocalClusteredQueue(office1, "node1", "sub6", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue6 = new LocalClusteredQueue(office1, 1, "sub6", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          
          Binding binding6 =
             office1.bindClusteredQueue("topic1", queue6);
          
-         LocalClusteredQueue queue7 = new LocalClusteredQueue(office1, "node1", "sub7", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue7 = new LocalClusteredQueue(office1, 1, "sub7", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          
          Binding binding7 =
             office1.bindClusteredQueue("topic1", queue7);
@@ -338,9 +338,9 @@
          assertEquivalent(binding6, (Binding)iter.next());
          
          //Restart office 1 and office 2
-         office1 = createClusteredPostOffice("node1", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
          
-         office2 = createClusteredPostOffice("node2", "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
          
          bindings = office1.listBindingsForCondition("topic1");
          assertNotNull(bindings);
@@ -373,9 +373,9 @@
          office3.stop();
          
          //Start them all
-         office1 = createClusteredPostOffice("node1", "testgroup");
-         office2 = createClusteredPostOffice("node2", "testgroup");
-         office3 = createClusteredPostOffice("node3", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
+         office3 = createClusteredPostOffice(3, "testgroup");
          
          //Only the durable queue should survive
          
@@ -494,19 +494,19 @@
           
       try
       {   
-         office1 = createClusteredPostOffice("node1", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
          
-         office2 = createClusteredPostOffice("node2", "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
          
-         LocalClusteredQueue queue1 = new LocalClusteredQueue(office1, "node1", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue1 = new LocalClusteredQueue(office1, 1, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          
          Binding binding1 = office1.bindClusteredQueue("queue1", queue1);
          
-         LocalClusteredQueue queue2 = new LocalClusteredQueue(office2, "node2", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue2 = new LocalClusteredQueue(office2, 2, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          
          Binding binding2 = office2.bindClusteredQueue("queue1", queue2);
                   
-         LocalClusteredQueue queue3 = new LocalClusteredQueue(office1, "node1", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue3 = new LocalClusteredQueue(office1, 1, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          
          try
          {
@@ -517,7 +517,7 @@
          {
             //Ok
          }
-         LocalClusteredQueue queue4 = new LocalClusteredQueue(office2, "node2", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue4 = new LocalClusteredQueue(office2, 2, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          
          try
          {
@@ -533,7 +533,7 @@
          
          office2.unbindClusteredQueue("queue1");
          
-         LocalClusteredQueue queue5 = new LocalClusteredQueue(office1, "node1", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue5 = new LocalClusteredQueue(office1, 1, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          
          Binding binding5 = office1.bindClusteredQueue("queue1", queue5);
          
@@ -598,21 +598,21 @@
           
       try
       {   
-         office1 = createClusteredPostOffice("node1", "testgroup");
-         office2 = createClusteredPostOffice("node2", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
          
          SimpleFilter filter1 = new SimpleFilter(2);
          SimpleFilter filter2 = new SimpleFilter(3);
       
-         LocalClusteredQueue queue1 = new LocalClusteredQueue(office1, "node1", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), filter1, tr);         
+         LocalClusteredQueue queue1 = new LocalClusteredQueue(office1, 1, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), filter1, tr);         
          Binding binding1 =
             office1.bindClusteredQueue("topic1", queue1);
          
-         LocalClusteredQueue queue2 = new LocalClusteredQueue(office2, "node2", "queue2", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), filter2, tr);         
+         LocalClusteredQueue queue2 = new LocalClusteredQueue(office2, 2, "queue2", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), filter2, tr);         
          Binding binding2 =
             office2.bindClusteredQueue("topic1", queue2);
          
-         LocalClusteredQueue queue3 = new LocalClusteredQueue(office2, "node2", "queue3", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue3 = new LocalClusteredQueue(office2, 2, "queue3", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding3 =
             office2.bindClusteredQueue("topic1", queue3);   
          
@@ -700,60 +700,60 @@
           
       try
       {   
-         office1 = createClusteredPostOffice("node1", "testgroup");
-         office2 = createClusteredPostOffice("node2", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
       
          //Two topics with a mixture of durable and non durable subscriptions
          
          LocalClusteredQueue[] queues = new LocalClusteredQueue[16];
          Binding[] bindings = new Binding[16];
          
-         queues[0] = new LocalClusteredQueue(office1, "node1", "sub1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[0] = new LocalClusteredQueue(office1, 1, "sub1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[0] = office1.bindClusteredQueue("topic1", queues[0]);
          
-         queues[1] = new LocalClusteredQueue(office1, "node1", "sub2", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[1] = new LocalClusteredQueue(office1, 1, "sub2", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[1] = office1.bindClusteredQueue("topic1", queues[1]);
          
-         queues[2] = new LocalClusteredQueue(office2, "node2", "sub3", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[2] = new LocalClusteredQueue(office2, 2, "sub3", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[2] = office2.bindClusteredQueue("topic1", queues[2]);
          
-         queues[3] = new LocalClusteredQueue(office2, "node2", "sub4", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[3] = new LocalClusteredQueue(office2, 2, "sub4", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[3] = office2.bindClusteredQueue("topic1", queues[3]);
          
-         queues[4] = new LocalClusteredQueue(office2, "node2", "sub5", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[4] = new LocalClusteredQueue(office2, 2, "sub5", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[4] = office2.bindClusteredQueue("topic1", queues[4]);
          
-         queues[5] = new LocalClusteredQueue(office1, "node1", "sub6", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[5] = new LocalClusteredQueue(office1, 1, "sub6", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[5] = office1.bindClusteredQueue("topic1", queues[5]);
          
-         queues[6] = new LocalClusteredQueue(office1, "node1", "sub7", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[6] = new LocalClusteredQueue(office1, 1, "sub7", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[6] = office1.bindClusteredQueue("topic1", queues[6]);
          
-         queues[7] = new LocalClusteredQueue(office1, "node1", "sub8", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[7] = new LocalClusteredQueue(office1, 1, "sub8", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[7] = office1.bindClusteredQueue("topic1", queues[7]);
          
-         queues[8] = new LocalClusteredQueue(office1, "node1", "sub9", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[8] = new LocalClusteredQueue(office1, 1, "sub9", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[8] = office1.bindClusteredQueue("topic2", queues[8]);
          
-         queues[9] = new LocalClusteredQueue(office1, "node1", "sub10", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[9] = new LocalClusteredQueue(office1, 1, "sub10", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[9] = office1.bindClusteredQueue("topic2", queues[9]);
          
-         queues[10] = new LocalClusteredQueue(office2, "node2", "sub11", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[10] = new LocalClusteredQueue(office2, 2, "sub11", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[10] = office2.bindClusteredQueue("topic2", queues[10]);
          
-         queues[11] = new LocalClusteredQueue(office2, "node2", "sub12", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[11] = new LocalClusteredQueue(office2, 2, "sub12", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[11] = office2.bindClusteredQueue("topic2", queues[11]);
          
-         queues[12] = new LocalClusteredQueue(office2, "node2", "sub13", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[12] = new LocalClusteredQueue(office2, 2, "sub13", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[12] = office2.bindClusteredQueue("topic2", queues[12]);
          
-         queues[13] = new LocalClusteredQueue(office1, "node1", "sub14", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[13] = new LocalClusteredQueue(office1, 1, "sub14", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[13] = office1.bindClusteredQueue("topic2", queues[13]);
          
-         queues[14] = new LocalClusteredQueue(office1, "node1", "sub15", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[14] = new LocalClusteredQueue(office1, 1, "sub15", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[14] = office1.bindClusteredQueue("topic2", queues[14]);
          
-         queues[15] = new LocalClusteredQueue(office1, "node1", "sub16", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[15] = new LocalClusteredQueue(office1, 1, "sub16", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[15] = office1.bindClusteredQueue("topic2", queues[15]);
        
          SimpleReceiver[] receivers = new SimpleReceiver[16];
@@ -885,37 +885,37 @@
         
       try
       {   
-         office1 = createClusteredPostOffice("node1", "testgroup");
-         office2 = createClusteredPostOffice("node2", "testgroup");
-         office3 = createClusteredPostOffice("node3", "testgroup");
-         office4 = createClusteredPostOffice("node4", "testgroup");
-         office5 = createClusteredPostOffice("node5", "testgroup");
-         office6 = createClusteredPostOffice("node6", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
+         office3 = createClusteredPostOffice(3, "testgroup");
+         office4 = createClusteredPostOffice(4, "testgroup");
+         office5 = createClusteredPostOffice(5, "testgroup");
+         office6 = createClusteredPostOffice(6, "testgroup");
     
          //We deploy the queue on nodes 1, 2, 3, 4 and 5
          //We don't deploy on node 6
          
-         LocalClusteredQueue queue1 = new LocalClusteredQueue(office1, "node1", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue1 = new LocalClusteredQueue(office1, 1, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding1 = office1.bindClusteredQueue("queue1", queue1);
          SimpleReceiver receiver1 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue1.add(receiver1);
          
-         LocalClusteredQueue queue2 = new LocalClusteredQueue(office2, "node2", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue2 = new LocalClusteredQueue(office2, 2, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding2 = office2.bindClusteredQueue("queue1", queue2); 
          SimpleReceiver receiver2 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue2.add(receiver2);
          
-         LocalClusteredQueue queue3 = new LocalClusteredQueue(office3, "node3", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue3 = new LocalClusteredQueue(office3, 3, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding3 = office3.bindClusteredQueue("queue1", queue3);
          SimpleReceiver receiver3 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue3.add(receiver3);
          
-         LocalClusteredQueue queue4 = new LocalClusteredQueue(office4, "node4", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue4 = new LocalClusteredQueue(office4, 4, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding4 = office4.bindClusteredQueue("queue1", queue4); 
          SimpleReceiver receiver4 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue4.add(receiver4);
          
-         LocalClusteredQueue queue5 = new LocalClusteredQueue(office5, "node5", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue queue5 = new LocalClusteredQueue(office5, 5, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding5 = office5.bindClusteredQueue("queue1", queue5);
          SimpleReceiver receiver5 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue5.add(receiver5);
@@ -1062,25 +1062,25 @@
         
       try
       {   
-         office1 = createClusteredPostOffice("node1", "testgroup");
-         office2 = createClusteredPostOffice("node2", "testgroup");
-         office3 = createClusteredPostOffice("node3", "testgroup");
-         office4 = createClusteredPostOffice("node4", "testgroup");
-         office5 = createClusteredPostOffice("node5", "testgroup");
-         office6 = createClusteredPostOffice("node6", "testgroup");
-         office7 = createClusteredPostOffice("node7", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
+         office3 = createClusteredPostOffice(3, "testgroup");
+         office4 = createClusteredPostOffice(4, "testgroup");
+         office5 = createClusteredPostOffice(5, "testgroup");
+         office6 = createClusteredPostOffice(6, "testgroup");
+         office7 = createClusteredPostOffice(7, "testgroup");
          
          //Node 2
          //======
          
          //Non durable 1 on node 2
-         LocalClusteredQueue nonDurable1 = new LocalClusteredQueue(office2, "node2", "nondurable1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue nonDurable1 = new LocalClusteredQueue(office2, 2, "nondurable1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding1 = office2.bindClusteredQueue("topic", nonDurable1);
          SimpleReceiver receiver1 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          nonDurable1.add(receiver1);
          
          //Non durable 2 on node 2
-         LocalClusteredQueue nonDurable2 = new LocalClusteredQueue(office2, "node2", "nondurable2", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue nonDurable2 = new LocalClusteredQueue(office2, 2, "nondurable2", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding2 = office2.bindClusteredQueue("topic", nonDurable2);
          SimpleReceiver receiver2 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          nonDurable2.add(receiver2);
@@ -1089,13 +1089,13 @@
          //======
          
          //Non shared durable
-         LocalClusteredQueue nonSharedDurable1 = new LocalClusteredQueue(office3, "node3", "nonshareddurable1", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue nonSharedDurable1 = new LocalClusteredQueue(office3, 3, "nonshareddurable1", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
          Binding binding3 = office3.bindClusteredQueue("topic", nonSharedDurable1);
          SimpleReceiver receiver3 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          nonSharedDurable1.add(receiver3);
          
          //Non durable
-         LocalClusteredQueue nonDurable3 = new LocalClusteredQueue(office3, "node3", "nondurable3", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue nonDurable3 = new LocalClusteredQueue(office3, 3, "nondurable3", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding4 = office3.bindClusteredQueue("topic", nonDurable3);
          SimpleReceiver receiver4 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          nonDurable3.add(receiver4);
@@ -1104,31 +1104,31 @@
          //======
          
          //Shared durable
-         LocalClusteredQueue sharedDurable1 = new LocalClusteredQueue(office4, "node4", "shareddurable1", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue sharedDurable1 = new LocalClusteredQueue(office4, 4, "shareddurable1", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
          Binding binding5 = office4.bindClusteredQueue("topic", sharedDurable1);
          SimpleReceiver receiver5 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          sharedDurable1.add(receiver5);
          
          //Non shared durable
-         LocalClusteredQueue nonSharedDurable2 = new LocalClusteredQueue(office4, "node4", "nonshareddurable2", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue nonSharedDurable2 = new LocalClusteredQueue(office4, 4, "nonshareddurable2", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
          Binding binding6 = office4.bindClusteredQueue("topic", nonSharedDurable2);
          SimpleReceiver receiver6 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          nonSharedDurable2.add(receiver6);
          
          //Non durable
-         LocalClusteredQueue nonDurable4 = new LocalClusteredQueue(office4, "node4", "nondurable4", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue nonDurable4 = new LocalClusteredQueue(office4, 4, "nondurable4", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding7 = office4.bindClusteredQueue("topic", nonDurable4);
          SimpleReceiver receiver7 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          nonDurable4.add(receiver7);
          
          // Non durable
-         LocalClusteredQueue nonDurable5 = new LocalClusteredQueue(office4, "node4", "nondurable5", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue nonDurable5 = new LocalClusteredQueue(office4, 4, "nondurable5", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding8 = office4.bindClusteredQueue("topic", nonDurable5);
          SimpleReceiver receiver8 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          nonDurable5.add(receiver8);
          
          //Non durable
-         LocalClusteredQueue nonDurable6 = new LocalClusteredQueue(office4, "node4", "nondurable6", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue nonDurable6 = new LocalClusteredQueue(office4, 4, "nondurable6", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding9 = office4.bindClusteredQueue("topic", nonDurable6);
          SimpleReceiver receiver9 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          nonDurable6.add(receiver9);
@@ -1136,32 +1136,32 @@
          // Node 5
          //=======
          //Shared durable
-         LocalClusteredQueue sharedDurable2 = new LocalClusteredQueue(office5, "node5", "shareddurable1", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue sharedDurable2 = new LocalClusteredQueue(office5, 5, "shareddurable1", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
          Binding binding10 = office5.bindClusteredQueue("topic", sharedDurable2);
          SimpleReceiver receiver10 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          sharedDurable2.add(receiver10);
          
          //Shared durable
-         LocalClusteredQueue sharedDurable3 = new LocalClusteredQueue(office5, "node5", "shareddurable2", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue sharedDurable3 = new LocalClusteredQueue(office5, 5, "shareddurable2", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
          Binding binding11 = office5.bindClusteredQueue("topic", sharedDurable3);
          SimpleReceiver receiver11 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          sharedDurable3.add(receiver11);
          
          // Node 6
          //=========
-         LocalClusteredQueue sharedDurable4 = new LocalClusteredQueue(office6, "node6", "shareddurable2", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue sharedDurable4 = new LocalClusteredQueue(office6, 6, "shareddurable2", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
          Binding binding12 = office6.bindClusteredQueue("topic", sharedDurable4);
          SimpleReceiver receiver12 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          sharedDurable4.add(receiver12);
          
-         LocalClusteredQueue nonDurable7 = new LocalClusteredQueue(office6, "node6", "nondurable7", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue nonDurable7 = new LocalClusteredQueue(office6, 6, "nondurable7", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);
          Binding binding13 = office6.bindClusteredQueue("topic", nonDurable7);
          SimpleReceiver receiver13 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          nonDurable7.add(receiver13);
          
          //Node 7
          //=======
-         LocalClusteredQueue sharedDurable5 = new LocalClusteredQueue(office7, "node7", "shareddurable2", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
+         LocalClusteredQueue sharedDurable5 = new LocalClusteredQueue(office7, 7, "shareddurable2", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);
          Binding binding14 = office7.bindClusteredQueue("topic", sharedDurable5);
          SimpleReceiver receiver14 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          sharedDurable5.add(receiver14);
@@ -1484,58 +1484,58 @@
       {   
          //Start two offices
          
-         office1 = createClusteredPostOffice("node1", "testgroup");
-         office2 = createClusteredPostOffice("node2", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
      
          LocalClusteredQueue[] queues = new LocalClusteredQueue[16];
          Binding[] bindings = new Binding[16];
          
-         queues[0] = new LocalClusteredQueue(office1, "node1", "sub1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[0] = new LocalClusteredQueue(office1, 1, "sub1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[0] = office1.bindClusteredQueue("topic1", queues[0]);
          
-         queues[1] = new LocalClusteredQueue(office1, "node1", "sub2", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[1] = new LocalClusteredQueue(office1, 1, "sub2", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[1] = office1.bindClusteredQueue("topic1", queues[1]);
          
-         queues[2] = new LocalClusteredQueue(office2, "node2", "sub3", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[2] = new LocalClusteredQueue(office2, 2, "sub3", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[2] = office2.bindClusteredQueue("topic1", queues[2]);
          
-         queues[3] = new LocalClusteredQueue(office2, "node2", "sub4", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[3] = new LocalClusteredQueue(office2, 2, "sub4", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[3] = office2.bindClusteredQueue("topic1", queues[3]);
          
-         queues[4] = new LocalClusteredQueue(office2, "node2", "sub5", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[4] = new LocalClusteredQueue(office2, 2, "sub5", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[4] = office2.bindClusteredQueue("topic1", queues[4]);
          
-         queues[5] = new LocalClusteredQueue(office1, "node1", "sub6", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[5] = new LocalClusteredQueue(office1, 1, "sub6", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[5] = office1.bindClusteredQueue("topic1", queues[5]);
          
-         queues[6] = new LocalClusteredQueue(office1, "node1", "sub7", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[6] = new LocalClusteredQueue(office1, 1, "sub7", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[6] = office1.bindClusteredQueue("topic1", queues[6]);
          
-         queues[7] = new LocalClusteredQueue(office1, "node1", "sub8", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[7] = new LocalClusteredQueue(office1, 1, "sub8", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[7] = office1.bindClusteredQueue("topic1", queues[7]);
          
-         queues[8] = new LocalClusteredQueue(office1, "node1", "sub9", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[8] = new LocalClusteredQueue(office1, 1, "sub9", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[8] = office1.bindClusteredQueue("topic2", queues[8]);
          
-         queues[9] = new LocalClusteredQueue(office1, "node1", "sub10", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[9] = new LocalClusteredQueue(office1, 1, "sub10", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[9] = office1.bindClusteredQueue("topic2", queues[9]);
          
-         queues[10] = new LocalClusteredQueue(office2, "node2", "sub11", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[10] = new LocalClusteredQueue(office2, 2, "sub11", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[10] = office2.bindClusteredQueue("topic2", queues[10]);
          
-         queues[11] = new LocalClusteredQueue(office2, "node2", "sub12", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[11] = new LocalClusteredQueue(office2, 2, "sub12", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[11] = office2.bindClusteredQueue("topic2", queues[11]);
          
-         queues[12] = new LocalClusteredQueue(office2, "node2", "sub13", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[12] = new LocalClusteredQueue(office2, 2, "sub13", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[12] = office2.bindClusteredQueue("topic2", queues[12]);
          
-         queues[13] = new LocalClusteredQueue(office1, "node1", "sub14", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         queues[13] = new LocalClusteredQueue(office1, 1, "sub14", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          bindings[13] = office1.bindClusteredQueue("topic2", queues[13]);
          
-         queues[14] = new LocalClusteredQueue(office1, "node1", "sub15", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[14] = new LocalClusteredQueue(office1, 1, "sub15", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[14] = office1.bindClusteredQueue("topic2", queues[14]);
          
-         queues[15] = new LocalClusteredQueue(office1, "node1", "sub16", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
+         queues[15] = new LocalClusteredQueue(office1, 1, "sub16", im.getId(), ms, pm, true, true, (QueuedExecutor)pool.get(), null, tr);         
          bindings[15] = office1.bindClusteredQueue("topic2", queues[15]);
 
          SimpleReceiver[] receivers = new SimpleReceiver[16];
@@ -2091,7 +2091,7 @@
       }
    }
    
-   protected ClusteredPostOffice createClusteredPostOffice(String nodeId, String groupName) throws Exception
+   protected ClusteredPostOffice createClusteredPostOffice(int nodeId, String groupName) throws Exception
    {
       MessagePullPolicy pullPolicy = new NullMessagePullPolicy();
       

Modified: trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultMessagePullPolicyTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultMessagePullPolicyTest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultMessagePullPolicyTest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -188,10 +188,10 @@
          this.msgCount = msgCount;
       }
 
-      public String getNodeId()
+      public int getNodeId()
       {
          // TODO Auto-generated method stub
-         return null;
+         return -1;
       }
 
       public QueueStats getStats()

Modified: trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultRouterTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultRouterTest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/DefaultRouterTest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -111,39 +111,39 @@
           
       try
       {   
-         office1 = createClusteredPostOffice("node1", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
          
-         office2 = createClusteredPostOffice("node2", "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
          
-         office3 = createClusteredPostOffice("node3", "testgroup");
+         office3 = createClusteredPostOffice(3, "testgroup");
          
-         office4 = createClusteredPostOffice("node4", "testgroup");
+         office4 = createClusteredPostOffice(4, "testgroup");
          
-         office5 = createClusteredPostOffice("node5", "testgroup");
+         office5 = createClusteredPostOffice(5, "testgroup");
          
-         office6 = createClusteredPostOffice("node6", "testgroup");
+         office6 = createClusteredPostOffice(6, "testgroup");
          
-         LocalClusteredQueue queue1 = new LocalClusteredQueue(office2, "node2", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue1 = new LocalClusteredQueue(office2, 2, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding1 = office2.bindClusteredQueue("topic", queue1);
          SimpleReceiver receiver1 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue1.add(receiver1);
          
-         LocalClusteredQueue queue2 = new LocalClusteredQueue(office3, "node3", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue2 = new LocalClusteredQueue(office3, 3, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding2 = office3.bindClusteredQueue("topic", queue2);
          SimpleReceiver receiver2 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue2.add(receiver2);
          
-         LocalClusteredQueue queue3 = new LocalClusteredQueue(office4, "node4", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue3 = new LocalClusteredQueue(office4, 4, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding3 = office4.bindClusteredQueue("topic", queue3);
          SimpleReceiver receiver3 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue3.add(receiver3);
          
-         LocalClusteredQueue queue4 = new LocalClusteredQueue(office5, "node5", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue4 = new LocalClusteredQueue(office5, 5, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding4 = office5.bindClusteredQueue("topic", queue4);
          SimpleReceiver receiver4 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue4.add(receiver4);
          
-         LocalClusteredQueue queue5 = new LocalClusteredQueue(office6, "node6", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue5 = new LocalClusteredQueue(office6, 6, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding5 = office6.bindClusteredQueue("topic", queue5);
          SimpleReceiver receiver5 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue5.add(receiver5);
@@ -250,39 +250,39 @@
           
       try
       {   
-         office1 = createClusteredPostOffice("node1", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
          
-         office2 = createClusteredPostOffice("node2", "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
          
-         office3 = createClusteredPostOffice("node3", "testgroup");
+         office3 = createClusteredPostOffice(3, "testgroup");
          
-         office4 = createClusteredPostOffice("node4", "testgroup");
+         office4 = createClusteredPostOffice(4, "testgroup");
          
-         office5 = createClusteredPostOffice("node5", "testgroup");
+         office5 = createClusteredPostOffice(5, "testgroup");
          
-         office6 = createClusteredPostOffice("node6", "testgroup");
+         office6 = createClusteredPostOffice(6, "testgroup");
          
-         LocalClusteredQueue queue1 = new LocalClusteredQueue(office2, "node2", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue1 = new LocalClusteredQueue(office2, 2, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding1 = office2.bindClusteredQueue("topic", queue1);
          SimpleReceiver receiver1 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue1.add(receiver1);
          
-         LocalClusteredQueue queue2 = new LocalClusteredQueue(office3, "node3", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue2 = new LocalClusteredQueue(office3, 3, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding2 = office3.bindClusteredQueue("topic", queue2);
          SimpleReceiver receiver2 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue2.add(receiver2);
          
-         LocalClusteredQueue queue3 = new LocalClusteredQueue(office4, "node4", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue3 = new LocalClusteredQueue(office4, 4, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding3 = office4.bindClusteredQueue("topic", queue3);
          SimpleReceiver receiver3 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue3.add(receiver3);
          
-         LocalClusteredQueue queue4 = new LocalClusteredQueue(office5, "node5", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue4 = new LocalClusteredQueue(office5, 5, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding4 = office5.bindClusteredQueue("topic", queue4);
          SimpleReceiver receiver4 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue4.add(receiver4);
          
-         LocalClusteredQueue queue5 = new LocalClusteredQueue(office6, "node6", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue5 = new LocalClusteredQueue(office6, 6, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding5 = office6.bindClusteredQueue("topic", queue5);
          SimpleReceiver receiver5 = new SimpleReceiver("blah", SimpleReceiver.ACCEPTING);
          queue5.add(receiver5);
@@ -368,7 +368,7 @@
    
    
    
-   protected ClusteredPostOffice createClusteredPostOffice(String nodeId, String groupName) throws Exception
+   protected ClusteredPostOffice createClusteredPostOffice(int nodeId, String groupName) throws Exception
    {
       MessagePullPolicy redistPolicy = new NullMessagePullPolicy();
       

Modified: trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/RedistributionTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/RedistributionTest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/tests/src/org/jboss/test/messaging/core/plugin/postoffice/cluster/RedistributionTest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -93,31 +93,31 @@
           
       try
       {   
-         office1 = createClusteredPostOffice("node1", "testgroup");
+         office1 = createClusteredPostOffice(1, "testgroup");
          
-         office2 = createClusteredPostOffice("node2", "testgroup");
+         office2 = createClusteredPostOffice(2, "testgroup");
          
-         office3 = createClusteredPostOffice("node3", "testgroup");
+         office3 = createClusteredPostOffice(3, "testgroup");
          
-         office4 = createClusteredPostOffice("node4", "testgroup");
+         office4 = createClusteredPostOffice(4, "testgroup");
          
-         office5 = createClusteredPostOffice("node5", "testgroup");
+         office5 = createClusteredPostOffice(5, "testgroup");
          
          log.info("Started offices");
          
-         LocalClusteredQueue queue1 = new LocalClusteredQueue(office1, "node1", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue1 = new LocalClusteredQueue(office1, 1, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding1 = office1.bindClusteredQueue("queue1", queue1);
                   
-         LocalClusteredQueue queue2 = new LocalClusteredQueue(office2, "node2", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue2 = new LocalClusteredQueue(office2, 2, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding2 = office2.bindClusteredQueue("queue1", queue2);
                   
-         LocalClusteredQueue queue3 = new LocalClusteredQueue(office3, "node3", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue3 = new LocalClusteredQueue(office3, 3, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding3 = office3.bindClusteredQueue("queue1", queue3);         
          
-         LocalClusteredQueue queue4 = new LocalClusteredQueue(office4, "node4", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue4 = new LocalClusteredQueue(office4, 4, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding4 = office4.bindClusteredQueue("queue1", queue4);
                   
-         LocalClusteredQueue queue5 = new LocalClusteredQueue(office5, "node5", "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
+         LocalClusteredQueue queue5 = new LocalClusteredQueue(office5, 5, "queue1", im.getId(), ms, pm, true, false, (QueuedExecutor)pool.get(), null, tr);         
          Binding binding5 = office5.bindClusteredQueue("queue1", queue5);
                   
          log.info("bound queues");
@@ -381,7 +381,7 @@
       
    }
    
-   protected ClusteredPostOffice createClusteredPostOffice(String nodeId, String groupName) throws Exception
+   protected ClusteredPostOffice createClusteredPostOffice(int nodeId, String groupName) throws Exception
    {
       MessagePullPolicy pullPolicy = new DefaultMessagePullPolicy();
       

Modified: trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -27,7 +27,6 @@
 import java.io.DataOutputStream;
 import java.io.EOFException;
 import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
@@ -1088,6 +1087,8 @@
       {
          int consumerID = 12345678;
          
+         int serverId = 76543;
+         
          JBossMessage m1 = new JBossMessage(123);
          JBossMessage m2 = new JBossMessage(456);
          JBossMessage m3 = new JBossMessage(789);
@@ -1106,7 +1107,7 @@
          msgs.add(del2);
          msgs.add(del3);         
          
-         ClientDelivery dr = new ClientDelivery(msgs, consumerID);
+         ClientDelivery dr = new ClientDelivery(msgs, serverId, consumerID);
          
          ByteArrayOutputStream bos = new ByteArrayOutputStream();
          
@@ -1132,6 +1133,9 @@
          //Second byte should be CALLBACK
          assertEquals(JMSWireFormat.CALLBACK, dis.readByte());
          
+         //Next int should be server id
+         assertEquals(76543, dis.readInt());
+         
          //Next int should be consumer id
          assertEquals(12345678, dis.readInt());
          
@@ -1204,7 +1208,8 @@
          
          List msgs2 = dr2.getMessages();
          
-         assertEquals(consumerID, dr2.getConsumerID());
+         assertEquals(serverId, dr2.getServerId());
+         assertEquals(consumerID, dr2.getConsumerId());
          
          MessageProxy p1 = (MessageProxy)msgs2.get(0);
          MessageProxy p2 = (MessageProxy)msgs2.get(1);

Modified: trunk/tests/src/org/jboss/test/messaging/tools/client/Colocated.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/tools/client/Colocated.java	2006-09-28 12:18:58 UTC (rev 1374)
+++ trunk/tests/src/org/jboss/test/messaging/tools/client/Colocated.java	2006-09-28 16:37:36 UTC (rev 1375)
@@ -56,7 +56,7 @@
       sc = new ServiceContainer("transaction,remoting", null);
       sc.start();
 
-      serverPeer = new ServerPeer("ServerPeer0", "/queue", "/topic");
+      serverPeer = new ServerPeer(0, "/queue", "/topic");
       serverPeer.start();
 
       deployTopic("T");




More information about the jboss-cvs-commits mailing list