[jboss-cvs] JBoss Messaging SVN: r1794 - in trunk: src/main/org/jboss/jms/client 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/delegate src/main/org/jboss/jms/message src/main/org/jboss/jms/server src/main/org/jboss/jms/server/endpoint src/main/org/jboss/jms/server/endpoint/advised src/main/org/jboss/jms/server/remoting src/main/org/jboss/jms/tx tests tests/src/org/jboss/test/messaging/jms tests/src/org/jboss/test/messaging/jms/clustering tests/src/org/jboss/test/messaging/tools/jboss tests/src/org/jboss/test/messaging/tools/jmx/rmi

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu Dec 14 14:33:11 EST 2006


Author: timfox
Date: 2006-12-14 14:32:42 -0500 (Thu, 14 Dec 2006)
New Revision: 1794

Added:
   trunk/src/main/org/jboss/jms/server/endpoint/Ack.java
   trunk/src/main/org/jboss/jms/server/endpoint/Cancel.java
   trunk/src/main/org/jboss/jms/server/endpoint/DefaultAck.java
   trunk/src/main/org/jboss/jms/server/endpoint/DeliveryInfo.java
   trunk/src/main/org/jboss/jms/server/endpoint/DeliveryRecovery.java
   trunk/src/main/org/jboss/jms/tx/ClientTransaction.java
Removed:
   trunk/src/main/org/jboss/jms/tx/AckInfo.java
   trunk/src/main/org/jboss/jms/tx/TxState.java
Modified:
   trunk/src/main/org/jboss/jms/client/Closeable.java
   trunk/src/main/org/jboss/jms/client/JBossConnectionConsumer.java
   trunk/src/main/org/jboss/jms/client/JBossSession.java
   trunk/src/main/org/jboss/jms/client/container/AsfAspect.java
   trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java
   trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java
   trunk/src/main/org/jboss/jms/client/container/FactoryAspect.java
   trunk/src/main/org/jboss/jms/client/container/HAAspect.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/container/TransactionAspect.java
   trunk/src/main/org/jboss/jms/client/delegate/ClientSessionDelegate.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/SessionState.java
   trunk/src/main/org/jboss/jms/delegate/ConnectionDelegate.java
   trunk/src/main/org/jboss/jms/delegate/SessionDelegate.java
   trunk/src/main/org/jboss/jms/message/BytesMessageProxy.java
   trunk/src/main/org/jboss/jms/message/JBossMessage.java
   trunk/src/main/org/jboss/jms/message/MapMessageProxy.java
   trunk/src/main/org/jboss/jms/message/MessageProxy.java
   trunk/src/main/org/jboss/jms/message/ObjectMessageProxy.java
   trunk/src/main/org/jboss/jms/message/StreamMessageProxy.java
   trunk/src/main/org/jboss/jms/message/TextMessageProxy.java
   trunk/src/main/org/jboss/jms/server/ServerPeer.java
   trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java
   trunk/src/main/org/jboss/jms/server/endpoint/ServerBrowserEndpoint.java
   trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.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/server/endpoint/SessionEndpoint.java
   trunk/src/main/org/jboss/jms/server/endpoint/advised/BrowserAdvised.java
   trunk/src/main/org/jboss/jms/server/endpoint/advised/ConnectionAdvised.java
   trunk/src/main/org/jboss/jms/server/endpoint/advised/ConsumerAdvised.java
   trunk/src/main/org/jboss/jms/server/endpoint/advised/SessionAdvised.java
   trunk/src/main/org/jboss/jms/server/remoting/JMSWireFormat.java
   trunk/src/main/org/jboss/jms/tx/ResourceManager.java
   trunk/src/main/org/jboss/jms/tx/TransactionRequest.java
   trunk/tests/build.xml
   trunk/tests/src/org/jboss/test/messaging/jms/AcknowledgementTest.java
   trunk/tests/src/org/jboss/test/messaging/jms/MessageConsumerTest.java
   trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java
   trunk/tests/src/org/jboss/test/messaging/jms/clustering/HATest.java
   trunk/tests/src/org/jboss/test/messaging/tools/jboss/MBeanConfigurationElement.java
   trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java
Log:
Major refactoring so deliveries are now managed by sessions.



Modified: trunk/src/main/org/jboss/jms/client/Closeable.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/Closeable.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/Closeable.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -47,7 +47,6 @@
     * @throws JMSException
     */
    void closing() throws JMSException;
-
-   boolean isClosed();
-  
+   
+   boolean isClosed() throws JMSException;
 }

Modified: trunk/src/main/org/jboss/jms/client/JBossConnectionConsumer.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/JBossConnectionConsumer.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/JBossConnectionConsumer.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -72,37 +72,37 @@
    
    // Attributes ----------------------------------------------------
    
-   protected ConsumerDelegate cons;
+   private ConsumerDelegate cons;
    
-   protected SessionDelegate sess;
+   private SessionDelegate sess;
    
-   protected int consumerID;
+   private int consumerID;
    
    /** The destination this consumer will receive messages from */
-   protected Destination destination;
+   private Destination destination;
    
    /** The ServerSessionPool that is implemented by the AS */
-   protected ServerSessionPool serverSessionPool;
+   private ServerSessionPool serverSessionPool;
    
    /** The maximum number of messages that a single session will be loaded with. */
-   protected int maxMessages;
+   private int maxMessages;
    
    /** Is the ConnectionConsumer closed? */
-   protected volatile boolean closed;
+   private volatile boolean closed;
      
    /** The "listening" thread that gets messages from destination and queues
    them for delivery to sessions */
-   protected Thread internalThread;
+   private Thread internalThread;
    
    /** The thread id */
-   protected int id;
+   private int id;
    
    /** The thread id generator */
-   protected static SynchronizedInt threadId = new SynchronizedInt(0);
+   private static SynchronizedInt threadId = new SynchronizedInt(0);
    
-   protected Object closeLock = new Object();      
+   private int maxDeliveries;
    
-   protected int maxDeliveries;
+   private long channelID;
    
    // Static --------------------------------------------------------
    
@@ -154,6 +154,8 @@
 
       this.consumerID = state.getConsumerID();      
       
+      this.channelID = state.getChannelId();
+      
       this.maxDeliveries = state.getMaxDeliveries();
 
       id = threadId.increment();
@@ -302,7 +304,7 @@
                for (int i = 0; i < mesList.size(); i++)
                {
                   MessageProxy m = (MessageProxy)mesList.get(i);
-                  session.addAsfMessage(m, consumerID, cons, maxDeliveries);
+                  session.addAsfMessage(m, consumerID, channelID, maxDeliveries);
                   if (trace) { log.trace("added " + m + " to session"); }
                }
 

Modified: trunk/src/main/org/jboss/jms/client/JBossSession.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/JBossSession.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/JBossSession.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -502,9 +502,9 @@
     * This method is used by the JBossConnectionConsumer to load up the session
     * with messages to be processed by the session's run() method
     */
-   void addAsfMessage(MessageProxy m, int consumerID, ConsumerDelegate cons, int maxDeliveries)
+   void addAsfMessage(MessageProxy m, int consumerID, long channelID, int maxDeliveries)
    {
-      delegate.addAsfMessage(m, consumerID, cons, maxDeliveries);
+      delegate.addAsfMessage(m, consumerID, channelID, maxDeliveries);
    }
       
    // Protected -----------------------------------------------------

Modified: trunk/src/main/org/jboss/jms/client/container/AsfAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/AsfAspect.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/AsfAspect.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -129,7 +129,7 @@
 
       MessageProxy m = (MessageProxy)mi.getArguments()[0];
       int theConsumerID = ((Integer)mi.getArguments()[1]).intValue();
-      ConsumerDelegate cons = (ConsumerDelegate)mi.getArguments()[2];
+      long channelID = ((Long)mi.getArguments()[2]).longValue();
       int maxDeliveries = ((Integer)mi.getArguments()[3]).intValue();
       
       if (m == null)
@@ -140,7 +140,7 @@
       AsfMessageHolder holder = new AsfMessageHolder();
       holder.msg = m;
       holder.consumerID = theConsumerID;
-      holder.consumerDelegate = cons;
+      holder.channelID = channelID;
       holder.maxDeliveries = maxDeliveries;
       
       msgs.add(holder);
@@ -164,7 +164,8 @@
 
          if (trace) { log.trace("sending " + holder.msg + " to the message listener" ); }
          
-         MessageCallbackHandler.callOnMessage(del, sessionListener, holder.consumerID, false,
+         MessageCallbackHandler.callOnMessage(del, sessionListener, holder.consumerID,
+                                              holder.channelID, false,
                                               holder.msg, ackMode, holder.maxDeliveries);                          
       }
       
@@ -184,11 +185,11 @@
 
    // Inner Classes --------------------------------------------------
    
-   protected static class AsfMessageHolder
+   private static class AsfMessageHolder
    {
-      MessageProxy msg;
-      int consumerID;
-      ConsumerDelegate consumerDelegate;
-      int maxDeliveries;
+      private MessageProxy msg;
+      private int consumerID;
+      private long channelID;
+      private int maxDeliveries;
    }
 }

Modified: trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/ClosedInterceptor.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -110,11 +110,6 @@
       return sb.toString();
    }
 
-   public boolean isClosed()
-   {
-      return state == IN_CLOSE || state == CLOSED;
-   }
-
    // Interceptor implementation -----------------------------------
 
    public String getName()
@@ -135,6 +130,7 @@
 
       if ("isClosed".equals(methodName))
       {
+         //Actually this is badly named, it returns true if it's closing as well as closed
          return new Boolean(isClosed());
       }
 
@@ -317,6 +313,11 @@
    // Package Private ------------------------------------------------
 
    // Private --------------------------------------------------------
+   
+   private boolean isClosed()
+   {
+      return state == IN_CLOSE || state == CLOSED;
+   }
 
    // Inner Classes --------------------------------------------------
 

Modified: trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/ConsumerAspect.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -74,6 +74,7 @@
       ConsumerState consumerState = (ConsumerState)((DelegateSupport)consumerDelegate).getState();
       int serverId = connectionState.getServerID();
       int consumerID = consumerState.getConsumerID();
+      long channelID = consumerState.getChannelId();
       int prefetchSize = consumerState.getPrefetchSize();
       QueuedExecutor sessionExecutor = sessionState.getExecutor();
       int maxDeliveries = consumerState.getMaxDeliveries();
@@ -81,12 +82,13 @@
       MessageCallbackHandler messageHandler =
          new MessageCallbackHandler(isCC, sessionState.getAcknowledgeMode(),
                                     sessionDelegate, consumerDelegate, consumerID,
+                                    channelID,
                                     prefetchSize, sessionExecutor, maxDeliveries);
       
       sessionState.addCallbackHandler(messageHandler);
       
       CallbackManager cm = connectionState.getRemotingConnection().getCallbackManager();
-      cm.registerHandler(serverId, consumerID, messageHandler);
+      cm.registerHandler(consumerID, messageHandler);
          
       consumerState.setMessageCallbackHandler(messageHandler);
       
@@ -115,7 +117,7 @@
       sessionState.removeCallbackHandler(consumerState.getMessageCallbackHandler());
 
       CallbackManager cm = connectionState.getRemotingConnection().getCallbackManager();
-      cm.unregisterHandler(connectionState.getServerID(), consumerState.getConsumerID());
+      cm.unregisterHandler(consumerState.getConsumerID());
             
       return res;
    }      

Modified: trunk/src/main/org/jboss/jms/client/container/FactoryAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/FactoryAspect.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/FactoryAspect.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -65,21 +65,21 @@
    {
       JBossMessage jbm = new JBossMessage(0);
        
-      return new MessageProxy(jbm, 0);
+      return new MessageProxy(jbm);
    }
    
    public Object handleCreateBytesMessage(Invocation invocation) throws Throwable
    {
       JBossBytesMessage jbm = new JBossBytesMessage(0);
          
-      return new BytesMessageProxy(jbm, 0);
+      return new BytesMessageProxy(jbm);
    }
    
    public Object handleCreateMapMessage(Invocation invocation) throws Throwable
    {
       JBossMapMessage jbm = new JBossMapMessage(0);
        
-      return new MapMessageProxy(jbm, 0);      
+      return new MapMessageProxy(jbm);      
    }
    
    public Object handleCreateObjectMessage(Invocation invocation) throws Throwable
@@ -93,14 +93,14 @@
          jbm.setObject((Serializable)mi.getArguments()[0]);
       }
       
-      return new ObjectMessageProxy(jbm, 0);
+      return new ObjectMessageProxy(jbm);
    }
    
    public Object handleCreateStreamMessage(Invocation invocation) throws Throwable
    {
       JBossStreamMessage jbm = new JBossStreamMessage(0);
       
-      return new StreamMessageProxy(jbm, 0);
+      return new StreamMessageProxy(jbm);
    }
    
    public Object handleCreateTextMessage(Invocation invocation) throws Throwable
@@ -114,7 +114,7 @@
          jbm.setText((String)mi.getArguments()[0]);
       }
       
-      return new TextMessageProxy(jbm, 0);
+      return new TextMessageProxy(jbm);
    }   
 
    // Package protected ---------------------------------------------

Modified: trunk/src/main/org/jboss/jms/client/container/HAAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/HAAspect.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/HAAspect.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -23,11 +23,10 @@
 package org.jboss.jms.client.container;
 
 import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import javax.jms.JMSException;
 
@@ -49,9 +48,11 @@
 import org.jboss.jms.client.state.HierarchicalStateSupport;
 import org.jboss.jms.client.state.ProducerState;
 import org.jboss.jms.client.state.SessionState;
+import org.jboss.jms.delegate.SessionDelegate;
 import org.jboss.jms.destination.JBossDestination;
 import org.jboss.jms.server.endpoint.CreateConnectionResult;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
+import org.jboss.jms.server.endpoint.DeliveryRecovery;
 import org.jboss.jms.tx.ResourceManager;
 import org.jboss.logging.Logger;
 import org.jboss.remoting.Client;
@@ -340,16 +341,21 @@
       // Transfer attributes from newDelegate to failedDelegate
       failedConnDelegate.copyAttributes(newConnDelegate);
 
-      int oldServerId = failedState.getServerID();
-
       CallbackManager oldCallbackManager = failedState.getRemotingConnection().getCallbackManager();
 
       //We need to update some of the attributes on the state
       failedState.copyState(newState);
+      
+      //Map of old session id to new session state
+      Map oldNewSessionStateMap = new HashMap();
 
       for(Iterator i = failedState.getChildren().iterator(); i.hasNext(); )
       {
          SessionState failedSessionState = (SessionState)i.next();
+         
+         if (trace) { log.trace("Failed session state has " + failedSessionState.getToAck().size() + " deliveries"); }
+         
+         int oldSessionId = failedSessionState.getSessionId();
 
          ClientSessionDelegate failedSessionDelegate =
             (ClientSessionDelegate)failedSessionState.getDelegate();
@@ -360,11 +366,15 @@
                                   failedSessionState.isXA());
 
          SessionState newSessionState = (SessionState)newSessionDelegate.getState();
+         
+         if (trace) { log.trace("New session state has " + newSessionState.getToAck().size() + " deliveries"); }
+         
+         oldNewSessionStateMap.put(new Integer(oldSessionId), failedSessionState);
 
          failedSessionDelegate.copyAttributes(newSessionDelegate);
 
          //We need to update some of the attributes on the state
-         newSessionState.copyState(newSessionState);
+         failedSessionState.copyState(newSessionState);
 
          if (trace) { log.trace("replacing session (" + failedSessionDelegate + ") with a new failover session " + newSessionDelegate); }
 
@@ -373,8 +383,6 @@
          // TODO Why is this clone necessary?
          children.addAll(failedSessionState.getChildren());
 
-         Set consumerIds = new HashSet();
-
          for (Iterator j = children.iterator(); j.hasNext(); )
          {
             HierarchicalStateSupport sessionChild = (HierarchicalStateSupport)j.next();
@@ -386,48 +394,58 @@
             else if (sessionChild instanceof ConsumerState)
             {
                handleFailoverOnConsumer(failedConnDelegate,
-                                        failedState,
-                                        failedSessionState,
                                         (ConsumerState)sessionChild,
                                         failedSessionDelegate,
-                                        oldServerId,
                                         oldCallbackManager);
-
-               // We add the new consumer id to the list of old ids
-               consumerIds.add(new Integer(((ConsumerState)sessionChild).getConsumerID()));
             }
             else if (sessionChild instanceof BrowserState)
             {
                 handleFailoverOnBrowser((BrowserState)sessionChild, newSessionDelegate);
             }
          }
-
-         /* Now we must sent the list of unacked AckInfos to the server - so the consumers
-          * delivery lists can be repopulated
-          */
+      }
+      
+      //First we must tell the resource manager to substitute old session id for new session id
+      //Note we MUST submit the entire mapping in one operation since there may be overlap between
+      //old and new session id, and we don't want to overwrite keys in the map
+      
+      failedState.getResourceManager().handleFailover(oldNewSessionStateMap);
+      
+      Iterator iter = oldNewSessionStateMap.values().iterator();
+            
+      while (iter.hasNext())
+      {
+         SessionState state = (SessionState)iter.next();
+         
          List ackInfos = null;
-
-         if (!failedSessionState.isTransacted() && !failedSessionState.isXA())
+         
+         if (!state.isTransacted() && !state.isXA())
          {
-            /*
-            Now we remove any unacked np messages - this is because we don't want to ack them
-            since the server won't know about them and will barf
-            */
+            //Now we remove any unacked np messages - this is because we don't want to ack them
+            //since the server won't know about them and will barf
+                        
+            Iterator iter2 = state.getToAck().iterator();
+            
+            if (trace) { log.trace("Removing any np deliveries"); }
 
-            Iterator iter = newSessionState.getToAck().iterator();
-
-            while (iter.hasNext())
+            while (iter2.hasNext())
             {
-               AckInfo info = (AckInfo)iter.next();
+               DeliveryInfo info = (DeliveryInfo)iter2.next();
 
-               if (!info.getMessage().getMessage().isReliable())
+               if (!info.getMessageProxy().getMessage().isReliable())
                {
-                  iter.remove();
+                  iter2.remove();
+                  
+                  if (trace) { log.trace("Removed np delivery: " + info.getDeliveryId()); }
                }
             }
+            
+            if (trace) { log.trace("Session is not transacted, retrieving deliveries from session state"); }
 
             //Get the ack infos from the list in the session state
-            ackInfos = failedSessionState.getToAck();
+            ackInfos = state.getToAck();
+            
+            if (trace) { log.trace("Retrieved " + ackInfos.size() + " deliveries"); }
          }
          else
          {
@@ -435,24 +453,36 @@
             //btw we have kept the old resource manager
             ResourceManager rm = failedState.getResourceManager();
 
-            // Remove any non persistent acks - so server doesn't barf on commit
-
-            rm.removeNonPersistentAcks(consumerIds);
-
-            ackInfos = rm.getAckInfosForConsumerIds(consumerIds);
+            ackInfos = rm.getDeliveriesForSession(state.getSessionId());
          }
 
          if (!ackInfos.isEmpty())
+         {                        
+            SessionDelegate newDelegate = (SessionDelegate)state.getDelegate();
+            
+            List recoveryInfos = new ArrayList();
+            
+            for (Iterator iter2 = ackInfos.iterator(); iter2.hasNext(); )
+            {
+               DeliveryInfo info = (DeliveryInfo)iter2.next();
+               
+               DeliveryRecovery recInfo =
+                  new DeliveryRecovery(info.getMessageProxy().getDeliveryId(),                                       
+                                       info.getMessageProxy().getMessage().getMessageID(),
+                                       info.getChannelId());
+               
+               recoveryInfos.add(recInfo);
+            }
+            
+            if (trace) { log.trace(this + " sending delivery recovery info: " + recoveryInfos); }
+            newDelegate.recoverDeliveries(recoveryInfos);
+         }
+         else
          {
-            log.info("Sending " + ackInfos.size() + " unacked");
-            newSessionDelegate.sendUnackedAckInfos(ackInfos);
+            if (trace) { log.trace(this + " no delivery recovery info to send"); }
          }
       }
 
-      //TODO
-      //If the session had consumers which are now closed then there is no way to recreate them on the server
-      //we need to store with session id
-
       // We must not start the connection until the end
       if (failedState.isStarted())
       {
@@ -463,11 +493,8 @@
    }
 
    private void handleFailoverOnConsumer(ClientConnectionDelegate failedConnectionDelegate,
-                                         ConnectionState failedConnectionState,
-                                         SessionState failedSessionState,
                                          ConsumerState failedConsumerState,
                                          ClientSessionDelegate failedSessionDelegate,
-                                         int oldServerID,
                                          CallbackManager oldCallbackManager)
       throws JMSException
    {
@@ -498,19 +525,21 @@
       // Update attributes on the old state
       failedConsumerState.copyState(newState);
 
-      if (failedSessionState.isTransacted() || failedSessionState.isXA())
-      {
-         // Replace the old consumer id with the new consumer id
+//      if (failedSessionState.isTransacted() || failedSessionState.isXA())
+//      {
+//         // Replace the old consumer id with the new consumer id
+//
+//         ResourceManager rm = failedConnectionState.getResourceManager();
+//
+//         todo - we need to replace the sesion id
+//         
+//         rm.handleFailover(oldConsumerID, failedConsumerState.getConsumerID());
+//      }
 
-         ResourceManager rm = failedConnectionState.getResourceManager();
-
-         rm.handleFailover(oldConsumerID, failedConsumerState.getConsumerID());
-      }
-
       // We need to re-use the existing message callback handler
 
       MessageCallbackHandler oldHandler =
-         oldCallbackManager.unregisterHandler(oldServerID, oldConsumerID);
+         oldCallbackManager.unregisterHandler(oldConsumerID);
 
       ConnectionState newConnectionState = (ConnectionState)failedConnectionDelegate.getState();
 
@@ -519,7 +548,7 @@
 
       // Remove the new handler
       MessageCallbackHandler newHandler = newCallbackManager.
-         unregisterHandler(newConnectionState.getServerID(), newState.getConsumerID());
+         unregisterHandler(newState.getConsumerID());
 
       log.debug("New handler is " + System.identityHashCode(newHandler));
 
@@ -528,8 +557,7 @@
 
       //Now we re-register the old handler with the new callback manager
 
-      newCallbackManager.registerHandler(newConnectionState.getServerID(),
-                                         newState.getConsumerID(),
+      newCallbackManager.registerHandler(newState.getConsumerID(),
                                          oldHandler);
 
       // We don't need to add the handler to the session state since it is already there - we

Modified: trunk/src/main/org/jboss/jms/client/container/SessionAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/SessionAspect.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/SessionAspect.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -36,7 +36,9 @@
 import org.jboss.jms.client.state.SessionState;
 import org.jboss.jms.delegate.SessionDelegate;
 import org.jboss.jms.message.MessageProxy;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.server.endpoint.Cancel;
+import org.jboss.jms.server.endpoint.DefaultAck;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
 import org.jboss.logging.Logger;
 import org.jboss.messaging.util.Util;
 
@@ -79,15 +81,16 @@
       List cancels = new ArrayList();
       for(Iterator i = state.getToAck().iterator(); i.hasNext(); )
       {
-         AckInfo ack = (AckInfo)i.next();
+         DeliveryInfo ack = (DeliveryInfo)i.next();
          if (ackMode == Session.AUTO_ACKNOWLEDGE ||
              ackMode == Session.DUPS_OK_ACKNOWLEDGE)
          {
-            acks.add(ack);            
+            acks.add(new DefaultAck(ack.getMessageProxy().getDeliveryId()));            
          }
          else
          {
-            cancels.add(ack);
+            Cancel cancel = new Cancel(ack.getMessageProxy().getDeliveryId(), ack.getMessageProxy().getDeliveryCount());
+            cancels.add(cancel);
          }
          i.remove();
       }
@@ -104,6 +107,7 @@
       }
       if (!cancels.isEmpty())
       {
+         log.info("Calling canceldeliveries: " + cancels.size());
          del.cancelDeliveries(cancels);
       }
 
@@ -136,25 +140,26 @@
           state.getCurrentTxId() == null)
       {
          // We collect acknowledgments (and not transact them) for CLIENT, AUTO and DUPS_OK, and
-         // also for XA sessions not enrolled in a global transaction.
-
-         SessionDelegate del = (SessionDelegate)mi.getTargetObject();
-         
+         // also for XA sessions not enlisted in a global transaction.
+ 
          // We store the ack in a list for later acknowledgement or recovery
     
          Object[] args = mi.getArguments();
-         MessageProxy mp = (MessageProxy)args[0];
-         int consumerID = ((Integer)args[1]).intValue();
-         AckInfo info = new AckInfo(mp, consumerID);
-         
+         DeliveryInfo info = (DeliveryInfo)args[0];
+
          state.getToAck().add(info);
          
-         if (trace) { log.trace("ack mode is " + Util.acknowledgmentModeToString(ackMode)+ ", acknowledged on " + del); }
+         if (trace)
+         { 
+            SessionDelegate del = (SessionDelegate)mi.getTargetObject();            
+            log.trace("ack mode is " + Util.acknowledgmentModeToString(ackMode)+ ", acknowledged on " + del);
+         }
       }
 
       return invocation.invokeNext();
    }
    
+   /* Used for client acknowledge */
    public Object handleAcknowledgeAll(Invocation invocation) throws Throwable
    {    
       MethodInvocation mi = (MethodInvocation)invocation;
@@ -187,7 +192,7 @@
       
       if (ackMode == Session.AUTO_ACKNOWLEDGE ||
           ackMode == Session.DUPS_OK_ACKNOWLEDGE ||
-          ackMode != Session.CLIENT_ACKNOWLEDGE && state.getCurrentTxId() == null)
+          (ackMode != Session.CLIENT_ACKNOWLEDGE && state.getCurrentTxId() == null))
       {
          // We acknowledge immediately on a non-transacted session that does not want to
          // CLIENT_ACKNOWLEDGE, or an XA session not enrolled in a global transaction.
@@ -207,16 +212,21 @@
                                                "There are " + acks.size());
             }
             
-            AckInfo ack = (AckInfo)acks.get(0);
+            DeliveryInfo ack = (DeliveryInfo)acks.get(0);
             
             if (cancel)
             {
-               sd.cancelDeliveries(acks);
+               List cancels = new ArrayList();
+               Cancel c = new Cancel(ack.getMessageProxy().getDeliveryId(), ack.getMessageProxy().getDeliveryCount());
+               cancels.add(c);
+               sd.cancelDeliveries(cancels);
             }
             else
             {
                sd.acknowledge(ack);
             }
+            
+            //TODO we can optimise this for the auto_ack case (i.e. not store in list and have to clear each time)
             state.getToAck().clear();
          }
          else
@@ -302,16 +312,17 @@
       // Need to be recovered in reverse order.
       for (int i = toRedeliver.size() - 1; i >= 0; i--)
       {
-         AckInfo info = (AckInfo)toRedeliver.get(i);
-         MessageProxy proxy = info.getMessage();        
+         DeliveryInfo info = (DeliveryInfo)toRedeliver.get(i);
+         MessageProxy proxy = info.getMessageProxy();        
          
-         MessageCallbackHandler handler = state.getCallbackHandler(info.getConsumerID());
+         MessageCallbackHandler handler = state.getCallbackHandler(info.getConsumerId());
               
          if (handler == null)
          {
             // This is ok. The original consumer has closed, this message wil get cancelled back
             // to the channel.
-            toCancel.addFirst(info);
+            Cancel cancel = new Cancel(info.getMessageProxy().getDeliveryId(), info.getMessageProxy().getDeliveryCount());
+            toCancel.addFirst(cancel);
          }
          else
          {

Modified: trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/StateCreationAspect.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -28,6 +28,7 @@
 import org.jboss.jms.client.delegate.ClientConnectionDelegate;
 import org.jboss.jms.client.delegate.ClientConsumerDelegate;
 import org.jboss.jms.client.delegate.ClientProducerDelegate;
+import org.jboss.jms.client.delegate.ClientSessionDelegate;
 import org.jboss.jms.client.delegate.DelegateSupport;
 import org.jboss.jms.client.remoting.JMSRemotingConnection;
 import org.jboss.jms.client.remoting.ConsolidatedRemotingConnectionListener;
@@ -40,7 +41,6 @@
 import org.jboss.jms.delegate.BrowserDelegate;
 import org.jboss.jms.delegate.ConnectionFactoryDelegate;
 import org.jboss.jms.delegate.ProducerDelegate;
-import org.jboss.jms.delegate.SessionDelegate;
 import org.jboss.jms.destination.JBossDestination;
 import org.jboss.jms.message.MessageIdGenerator;
 import org.jboss.jms.message.MessageIdGeneratorFactory;
@@ -132,7 +132,7 @@
 
    public Object handleCreateSessionDelegate(Invocation invocation) throws Throwable
    {
-      SessionDelegate sessionDelegate = (SessionDelegate)invocation.invokeNext();
+      ClientSessionDelegate sessionDelegate = (ClientSessionDelegate)invocation.invokeNext();
       DelegateSupport delegate = (DelegateSupport)sessionDelegate;
 
       delegate.init();

Modified: trunk/src/main/org/jboss/jms/client/container/TransactionAspect.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/container/TransactionAspect.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/container/TransactionAspect.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -32,8 +32,8 @@
 import org.jboss.jms.client.state.HierarchicalState;
 import org.jboss.jms.client.state.SessionState;
 import org.jboss.jms.delegate.ConnectionDelegate;
-import org.jboss.jms.message.MessageProxy;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.message.JBossMessage;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
 import org.jboss.jms.tx.LocalTx;
 import org.jboss.jms.tx.ResourceManager;
 import org.jboss.logging.Logger;
@@ -164,7 +164,7 @@
 
          if (trace) { log.trace("sending message " + m + " transactionally, queueing on resource manager"); }
 
-         connState.getResourceManager().addMessage(txID, m);
+         connState.getResourceManager().addMessage(txID, state.getSessionId(), (JBossMessage)m);
 
          // ... and we don't invoke any further interceptors in the stack
          return null;
@@ -185,16 +185,16 @@
          // the session is non-XA and transacted, or XA and enrolled in a global transaction. An
          // XA session that has not been enrolled in a global transaction behaves as a
          // non-transacted session.
+         
+         MethodInvocation mi = (MethodInvocation)invocation;
+         
+         DeliveryInfo info = (DeliveryInfo)mi.getArguments()[0];
 
-         MethodInvocation mi = (MethodInvocation)invocation;
-         MessageProxy proxy = (MessageProxy)mi.getArguments()[0];
-         int consumerID = ((Integer)mi.getArguments()[1]).intValue();
-         AckInfo info = new AckInfo(proxy, consumerID);
          ConnectionState connState = (ConnectionState)state.getParent();
 
          if (trace) { log.trace("sending acknowlegment transactionally, queueing on resource manager"); }
 
-         connState.getResourceManager().addAck(txID, info);
+         connState.getResourceManager().addAck(txID, state.getSessionId(), info);
       }
 
       return null;

Modified: trunk/src/main/org/jboss/jms/client/delegate/ClientSessionDelegate.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/delegate/ClientSessionDelegate.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/delegate/ClientSessionDelegate.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -43,7 +43,8 @@
 import org.jboss.jms.message.ObjectMessageProxy;
 import org.jboss.jms.message.StreamMessageProxy;
 import org.jboss.jms.message.TextMessageProxy;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.server.endpoint.Ack;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
 import org.jboss.remoting.Client;
 
 /**
@@ -111,7 +112,7 @@
     * This invocation should either be handled by the client-side interceptor chain or by the
     * server-side endpoint.
     */
-   public void acknowledge(AckInfo ackInfo) throws JMSException
+   public void acknowledge(Ack ack) throws JMSException
    {
       throw new IllegalStateException("This invocation should not be handled here!");
    }
@@ -120,7 +121,7 @@
     * This invocation should either be handled by the client-side interceptor chain or by the
     * server-side endpoint.
     */
-   public void acknowledgeBatch(List ackInfos) throws JMSException
+   public void acknowledgeBatch(List acks) throws JMSException
    {
       throw new IllegalStateException("This invocation should not be handled here!");
    }
@@ -313,7 +314,7 @@
     * This invocation should either be handled by the client-side interceptor chain or by the
     * server-side endpoint.
     */
-   public void preDeliver(MessageProxy proxy, int consumerID) throws JMSException
+   public void preDeliver(DeliveryInfo deliveryInfo) throws JMSException
    {
       throw new IllegalStateException("This invocation should not be handled here!");
    }
@@ -404,8 +405,7 @@
     * This invocation should either be handled by the client-side interceptor chain or by the
     * server-side endpoint.
     */
-   public void addAsfMessage(MessageProxy m, int consumerID,
-                             ConsumerDelegate cons, int maxDeliveries)
+   public void addAsfMessage(MessageProxy m, int consumerID, long channelId, int maxDeliveries)
    {
       throw new IllegalStateException("This invocation should not be handled here!");
    }
@@ -432,7 +432,7 @@
     * This invocation should either be handled by the client-side interceptor chain or by the
     * server-side endpoint.
     */
-   public void sendUnackedAckInfos(List ackInfos) throws JMSException
+   public void recoverDeliveries(List ackInfos) throws JMSException
    {
       throw new IllegalStateException("This invocation should not be handled here!");
    }

Modified: trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/remoting/CallbackManager.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -40,6 +40,9 @@
  * The CallbackManager is an InvocationHandler used for handling callbacks to message consumers.
  * The callback is received and dispatched off to the relevant consumer.
  * 
+ * There is one instance of this class per remoting connection - which is to a unique server - therefore
+ * there is no need to add the server id to the key when doing look ups
+ * 
  * @author <a href="tim.fox at jboss.com">Tim Fox</a>
  * @author <a href="ovidiu at jboss.org">Ovidiu Feodorov</a>
  * @version 1.1
@@ -76,15 +79,13 @@
    {
       MessagingMarshallable mm = (MessagingMarshallable)callback.getParameter();
       ClientDelivery dr = (ClientDelivery)mm.getLoad();
-      Long lookup = computeLookup(dr.getServerId(), dr.getConsumerId());
       List msgs = dr.getMessages();
 
-      MessageCallbackHandler handler = (MessageCallbackHandler)callbackHandlers.get(lookup);
+      MessageCallbackHandler handler = (MessageCallbackHandler)callbackHandlers.get(new Integer(dr.getConsumerId()));
 
       if (handler == null)
       {
-         throw new IllegalStateException("Cannot find handler for consumer: " + dr.getConsumerId() +
-                                         " and server " + dr.getServerId());
+         throw new IllegalStateException("Cannot find handler for consumer: " + dr.getConsumerId());
       }
 
       handler.handleMessage(msgs);
@@ -92,18 +93,14 @@
 
    // Public --------------------------------------------------------
 
-   public void registerHandler(int serverID, int consumerID, MessageCallbackHandler handler)
+   public void registerHandler(int consumerID, MessageCallbackHandler handler)
    {
-      Long lookup = computeLookup(serverID, consumerID);
-
-      callbackHandlers.put(lookup, handler);
+      callbackHandlers.put(new Integer(consumerID), handler);
    }
 
-   public MessageCallbackHandler unregisterHandler(int serverID, int consumerID)
+   public MessageCallbackHandler unregisterHandler(int consumerID)
    { 
-      Long lookup = computeLookup(serverID, consumerID);
-
-      return (MessageCallbackHandler)callbackHandlers.remove(lookup);
+      return (MessageCallbackHandler)callbackHandlers.remove(new Integer(consumerID));
    }
 
    // Package protected ---------------------------------------------
@@ -112,17 +109,6 @@
 
    // Private -------------------------------------------------------
 
-   private Long computeLookup(int serverID, int consumerID)
-   {
-      long id1 = serverID;
-
-      id1 <<= 32;
-
-      long lookup = id1 | consumerID;
-
-      return new Long(lookup);
-   }
-
    // Inner classes -------------------------------------------------
 
 }

Modified: trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/remoting/MessageCallbackHandler.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -34,9 +34,9 @@
 import org.jboss.jms.delegate.ConsumerDelegate;
 import org.jboss.jms.delegate.SessionDelegate;
 import org.jboss.jms.message.MessageProxy;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.server.endpoint.Cancel;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
 import org.jboss.logging.Logger;
-import org.jboss.messaging.core.Message;
 import org.jboss.messaging.util.Future;
 import org.jboss.remoting.callback.HandleCallbackException;
 
@@ -68,13 +68,14 @@
    public static void callOnMessage(SessionDelegate sess,
                                     MessageListener listener,
                                     int consumerID,
+                                    long channelID,
                                     boolean isConnectionConsumer,
                                     MessageProxy m,
                                     int ackMode,
                                     int maxDeliveries)
       throws JMSException
    {
-      preDeliver(sess, consumerID, m, isConnectionConsumer);
+      preDeliver(sess, consumerID, channelID, m, isConnectionConsumer);
                   
       int tries = 0;
       
@@ -141,6 +142,7 @@
    
    protected static void preDeliver(SessionDelegate sess,
                                     int consumerID,
+                                    long channelID,
                                     MessageProxy m,
                                     boolean isConnectionConsumer)
       throws JMSException
@@ -149,7 +151,7 @@
       // add anything to the tx for this session.
       if (!isConnectionConsumer)
       {
-         sess.preDeliver(m, consumerID);
+         sess.preDeliver(new DeliveryInfo(m, consumerID, channelID));
       }         
    }
    
@@ -181,11 +183,13 @@
    private QueuedExecutor sessionExecutor;
    private boolean listenerRunning;
    private int maxDeliveries;
+   private long channelID;
         
    // Constructors --------------------------------------------------
 
    public MessageCallbackHandler(boolean isCC, int ackMode,                                
                                  SessionDelegate sess, ConsumerDelegate cons, int consumerID,
+                                 long channelID,
                                  int bufferSize, QueuedExecutor sessionExecutor,
                                  int maxDeliveries)
    {
@@ -201,6 +205,7 @@
       this.sessionDelegate = sess;
       this.consumerDelegate = cons;
       this.consumerID = consumerID;
+      this.channelID = channelID;
       this.serverSending = true;
       mainLock = new Object();
       this.sessionExecutor = sessionExecutor;
@@ -281,7 +286,7 @@
          }        
       }   
    }
-      
+   
    public void close() throws JMSException
    {   
       synchronized (mainLock)
@@ -321,16 +326,16 @@
          // have actually been delivered (unlike these) and we may want to acknowledge them
          // later, after this consumer has been closed
 
-         List ackInfos = new ArrayList();
+         List cancels = new ArrayList();
 
          for(Iterator i = buffer.iterator(); i.hasNext();)
          {
             MessageProxy mp = (MessageProxy)i.next();
-            AckInfo ack = new AckInfo(mp, consumerID);
-            ackInfos.add(ack);
+            Cancel ack = new Cancel(mp.getDeliveryId(), mp.getDeliveryCount());
+            cancels.add(ack);
          }
                
-         sessionDelegate.cancelDeliveries(ackInfos);
+         sessionDelegate.cancelDeliveries(cancels);
          
          buffer.clear();
       }                
@@ -445,7 +450,7 @@
                        
                // If message is expired we still call pre and post deliver. This makes sure the
                // message is acknowledged so it gets removed from the queue/subscription.
-               preDeliver(sessionDelegate, consumerID, m, isConnectionConsumer);
+               preDeliver(sessionDelegate, consumerID, channelID, m, isConnectionConsumer);
                
                postDeliver(sessionDelegate, isConnectionConsumer, false);
                
@@ -726,7 +731,7 @@
          {
             try
             {
-               callOnMessage(sessionDelegate, listener, consumerID, false, mp, ackMode, maxDeliveries);
+               callOnMessage(sessionDelegate, listener, consumerID, channelID, false, mp, ackMode, maxDeliveries);
             }
             catch (JMSException e)
             {

Modified: trunk/src/main/org/jboss/jms/client/state/SessionState.java
===================================================================
--- trunk/src/main/org/jboss/jms/client/state/SessionState.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/client/state/SessionState.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -27,8 +27,9 @@
 import java.util.List;
 import java.util.Map;
 
+import org.jboss.jms.client.delegate.ClientSessionDelegate;
+import org.jboss.jms.client.delegate.DelegateSupport;
 import org.jboss.jms.client.remoting.MessageCallbackHandler;
-import org.jboss.jms.client.delegate.DelegateSupport;
 import org.jboss.jms.delegate.SessionDelegate;
 import org.jboss.jms.server.Version;
 import org.jboss.jms.tx.MessagingXAResource;
@@ -50,6 +51,8 @@
 {
    protected static Logger log = Logger.getLogger(SessionState.class);
 
+   private int sessionId;
+   
    private int acknowledgeMode;
    
    private boolean transacted;
@@ -74,10 +77,13 @@
    
    private Map callbackHandlers;
    
-   public SessionState(ConnectionState parent, SessionDelegate delegate,
-            boolean transacted, int ackMode, boolean xa)
+   public SessionState(ConnectionState parent, ClientSessionDelegate delegate,
+                       boolean transacted, int ackMode, boolean xa)
    {
       super(parent, (DelegateSupport)delegate);
+      
+      this.sessionId = delegate.getID();
+      
       children = new HashSet();
       this.acknowledgeMode = ackMode;
       this.transacted = transacted;
@@ -206,12 +212,18 @@
       return new ArrayList(callbackHandlers.values());
    }
    
+   public int getSessionId()
+   {
+      return sessionId;
+   }
+   
    // When failing over a session, we keep the old session's state but there are certain fields
    // we need to update
    public void copyState(SessionState newState)
    {      
-      //Actually only one field
       this.delegate = newState.delegate;
+      
+      this.sessionId = newState.sessionId;
    }
 }
 

Modified: trunk/src/main/org/jboss/jms/delegate/ConnectionDelegate.java
===================================================================
--- trunk/src/main/org/jboss/jms/delegate/ConnectionDelegate.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/delegate/ConnectionDelegate.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -53,10 +53,4 @@
                                                     String messageSelector,
                                                     ServerSessionPool sessionPool,
                                                     int maxMessages) throws JMSException;
-
-   /**
-    * Reconnects the current connection hierarchy using newConnection's properties.
-    */
-    //void failOver(ConnectionDelegate newConnection);
-
 }

Modified: trunk/src/main/org/jboss/jms/delegate/SessionDelegate.java
===================================================================
--- trunk/src/main/org/jboss/jms/delegate/SessionDelegate.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/delegate/SessionDelegate.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -35,6 +35,7 @@
 import org.jboss.jms.message.ObjectMessageProxy;
 import org.jboss.jms.message.StreamMessageProxy;
 import org.jboss.jms.message.TextMessageProxy;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
 import org.jboss.jms.server.endpoint.SessionEndpoint;
 
 /**
@@ -65,7 +66,7 @@
    
    TextMessageProxy createTextMessage(String text) throws JMSException;
    
-   void preDeliver(MessageProxy proxy, int consumerID) throws JMSException;
+   void preDeliver(DeliveryInfo deliveryInfo) throws JMSException;
    
    void postDeliver(boolean cancel) throws JMSException;
    
@@ -77,7 +78,7 @@
    
    XAResource getXAResource();
    
-   void addAsfMessage(MessageProxy m, int consumerID, ConsumerDelegate cons, int maxDeliveries);
+   void addAsfMessage(MessageProxy m, int consumerID, long channelID, int maxDeliveries);
    
    boolean getTransacted();
    
@@ -89,7 +90,7 @@
    
    void recover() throws JMSException;
    
-   void redeliver(List ackInfos) throws JMSException;
+   void redeliver(List deliveryInfos) throws JMSException;
    
    ProducerDelegate createProducerDelegate(JBossDestination destination) throws JMSException;
    

Modified: trunk/src/main/org/jboss/jms/message/BytesMessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/BytesMessageProxy.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/BytesMessageProxy.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -38,10 +38,15 @@
 {
    private static final long serialVersionUID = -9121097962625801946L;
 
-   public BytesMessageProxy(JBossBytesMessage message, int deliveryCount)
+   public BytesMessageProxy(long deliveryId, JBossBytesMessage message, int deliveryCount)
    {
-      super(message, deliveryCount);
+      super(deliveryId, message, deliveryCount);
    }
+   
+   public BytesMessageProxy(JBossBytesMessage message)
+   {
+      super(message);
+   }
 
    public long getBodyLength() throws JMSException
    {

Modified: trunk/src/main/org/jboss/jms/message/JBossMessage.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/JBossMessage.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/JBossMessage.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -104,33 +104,33 @@
       reservedIdentifiers.add("ESCAPE");
    }
 
-   public static MessageProxy createThinDelegate(JBossMessage m, int deliveryCount)
+   public static MessageProxy createThinDelegate(long deliveryId, JBossMessage m, int deliveryCount)
    {
       MessageProxy del;
       
       if (m instanceof BytesMessage)
       {
-         del = new BytesMessageProxy((JBossBytesMessage)m, deliveryCount);
+         del = new BytesMessageProxy(deliveryId, (JBossBytesMessage)m, deliveryCount);
       }
       else if (m instanceof MapMessage)
       {
-         del = new MapMessageProxy((JBossMapMessage)m, deliveryCount);
+         del = new MapMessageProxy(deliveryId, (JBossMapMessage)m, deliveryCount);
       }
       else if (m instanceof ObjectMessage)
       {
-         del = new ObjectMessageProxy((JBossObjectMessage)m, deliveryCount);
+         del = new ObjectMessageProxy(deliveryId, (JBossObjectMessage)m, deliveryCount);
       }
       else if (m instanceof StreamMessage)
       {
-         del = new StreamMessageProxy((JBossStreamMessage)m, deliveryCount);
+         del = new StreamMessageProxy(deliveryId, (JBossStreamMessage)m, deliveryCount);
       }
       else if (m instanceof TextMessage)
       {
-         del = new TextMessageProxy((JBossTextMessage)m, deliveryCount);
+         del = new TextMessageProxy(deliveryId, (JBossTextMessage)m, deliveryCount);
       }      
       else
       {
-         del = new MessageProxy(m, deliveryCount);
+         del = new MessageProxy(deliveryId, m, deliveryCount);
       }
 
       return del;

Modified: trunk/src/main/org/jboss/jms/message/MapMessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/MapMessageProxy.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/MapMessageProxy.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -39,11 +39,16 @@
 {
    private static final long serialVersionUID = 6953530870351885569L;
 
-   public MapMessageProxy(JBossMapMessage message, int deliveryCount)
+   public MapMessageProxy(long deliveryId, JBossMapMessage message, int deliveryCount)
    {
-      super(message, deliveryCount);
+      super(deliveryId, message, deliveryCount);
    }
    
+   public MapMessageProxy(JBossMapMessage message)
+   {
+      super(message);
+   }
+   
    public boolean getBoolean(String name) throws JMSException
    {
       return ((MapMessage)message).getBoolean(name);

Modified: trunk/src/main/org/jboss/jms/message/MessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/MessageProxy.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/MessageProxy.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -65,30 +65,46 @@
 
    // Attributes ----------------------------------------------------
 
-   protected JBossMessage message;
-
-   protected transient SessionDelegate delegate;
+   private transient SessionDelegate delegate;
    
-   protected transient boolean cc;
-   protected transient boolean messageCopied;
-   protected transient boolean propertiesCopied;
-   protected transient boolean bodyCopied;
+   private transient boolean cc;
+   
+   private transient boolean messageCopied;
+   
+   private transient boolean propertiesCopied;
+   
+   private transient boolean bodyCopied;
 
-   protected transient int state;
+   private transient int state;
 
-   protected transient boolean propertiesReadOnly;
+   private transient boolean propertiesReadOnly;   
+
+   private int deliveryCount;
+   
+   private long deliveryId;
+   
    protected transient boolean bodyReadOnly;
+   
+   protected JBossMessage message;
 
-   protected int deliveryCount;
 
    // Constructors --------------------------------------------------
 
    public MessageProxy()
    {
    }
+   
+   public MessageProxy(JBossMessage message)
+   {
+      this.deliveryId = -1;
+      this.message = message;
+      this.state = STATE_NEW;
+      this.deliveryCount = 0;
+   }
 
-   public MessageProxy(JBossMessage message, int deliveryCount)
+   public MessageProxy(long deliveryId, JBossMessage message, int deliveryCount)
    {
+      this.deliveryId = deliveryId;
       this.message = message;
       this.state = STATE_NEW;
       this.deliveryCount = deliveryCount;
@@ -433,6 +449,11 @@
    {
       this.deliveryCount++;            
    }
+   
+   public long getDeliveryId()
+   {
+      return deliveryId;
+   }
 
    public String toString()
    {

Modified: trunk/src/main/org/jboss/jms/message/ObjectMessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/ObjectMessageProxy.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/ObjectMessageProxy.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -39,10 +39,15 @@
 {
    private static final long serialVersionUID = 8797295997477962825L;
 
-   public ObjectMessageProxy(JBossObjectMessage message, int deliveryCount)
+   public ObjectMessageProxy(long deliveryId, JBossObjectMessage message, int deliveryCount)
    {
-      super(message, deliveryCount);
+      super(deliveryId, message, deliveryCount);
    }
+   
+   public ObjectMessageProxy(JBossObjectMessage message)
+   {
+      super(message);
+   }
 
    public void setObject(Serializable object) throws JMSException
    {

Modified: trunk/src/main/org/jboss/jms/message/StreamMessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/StreamMessageProxy.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/StreamMessageProxy.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -38,10 +38,15 @@
 {
    private static final long serialVersionUID = 856367553964704474L;
 
-   public StreamMessageProxy(JBossStreamMessage message, int deliveryCount)
+   public StreamMessageProxy(long deliveryId, JBossStreamMessage message, int deliveryCount)
    {
-      super(message, deliveryCount);
+      super(deliveryId, message, deliveryCount);
    }
+   
+   public StreamMessageProxy(JBossStreamMessage message)
+   {
+      super(message);
+   }
 
    public boolean readBoolean() throws JMSException
    {

Modified: trunk/src/main/org/jboss/jms/message/TextMessageProxy.java
===================================================================
--- trunk/src/main/org/jboss/jms/message/TextMessageProxy.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/message/TextMessageProxy.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -34,14 +34,18 @@
  */
 public class TextMessageProxy extends MessageProxy implements TextMessage
 {
-
    private static final long serialVersionUID = -3530143417050205123L;
 
-   public TextMessageProxy(JBossTextMessage message, int deliveryCount)
+   public TextMessageProxy(long deliveryId, JBossTextMessage message, int deliveryCount)
    {
-      super(message, deliveryCount);
+      super(deliveryId, message, deliveryCount);
    }
    
+   public TextMessageProxy(JBossTextMessage message)
+   {
+      super(message);
+   }
+   
    public void setText(String string) throws JMSException
    {
       if (bodyReadOnly)

Modified: trunk/src/main/org/jboss/jms/server/ServerPeer.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/ServerPeer.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/ServerPeer.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -37,10 +37,9 @@
 import org.jboss.jms.server.connectionfactory.ConnectionFactoryJNDIMapper;
 import org.jboss.jms.server.connectionmanager.SimpleConnectionManager;
 import org.jboss.jms.server.connectormanager.SimpleConnectorManager;
-import org.jboss.jms.server.endpoint.ServerConsumerEndpoint;
 import org.jboss.jms.server.plugin.contract.JMSUserManager;
-import org.jboss.jms.server.remoting.JMSWireFormat;
 import org.jboss.jms.server.remoting.JMSServerInvocationHandler;
+import org.jboss.jms.server.remoting.JMSWireFormat;
 import org.jboss.jms.server.security.SecurityMetadataStore;
 import org.jboss.jms.util.ExceptionUtil;
 import org.jboss.logging.Logger;
@@ -54,20 +53,18 @@
 import org.jboss.messaging.core.plugin.contract.PostOffice;
 import org.jboss.messaging.core.plugin.contract.ReplicationListener;
 import org.jboss.messaging.core.plugin.contract.Replicator;
+import org.jboss.messaging.core.plugin.postoffice.Binding;
 import org.jboss.messaging.core.plugin.postoffice.cluster.DefaultClusteredPostOffice;
 import org.jboss.messaging.core.plugin.postoffice.cluster.FailoverStatus;
-import org.jboss.messaging.core.plugin.postoffice.Binding;
 import org.jboss.messaging.core.tx.TransactionRepository;
 import org.jboss.messaging.util.Util;
 import org.jboss.mx.loading.UnifiedClassLoader3;
-import org.jboss.remoting.marshal.MarshalFactory;
 import org.jboss.remoting.ServerInvocationHandler;
+import org.jboss.remoting.marshal.MarshalFactory;
 import org.jboss.system.ServiceCreator;
 import org.jboss.system.ServiceMBeanSupport;
 import org.w3c.dom.Element;
 
-import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
-
 /**
  * A JMS server peer.
  *
@@ -146,14 +143,6 @@
 
    private JMSServerInvocationHandler handler;
 
-   // We keep a map of consumers to prevent us to recurse through the attached session in order to
-   // find the ServerConsumerDelegate so we can acknowledge the message. Originally, this map was
-   // maintained per-connection, but with the http://jira.jboss.org/jira/browse/JBMESSAGING-211 bug
-   // we shared it among connections, so a transaction submitted on the "wrong" connection can
-   // still succeed. For more details, see the JIRA issue.
-
-   private Map consumers;
-
    // Constructors --------------------------------------------------
 
    public ServerPeer(int serverPeerID,
@@ -167,8 +156,6 @@
       // Some wired components need to be started here
       securityStore = new SecurityMetadataStore();
 
-      consumers = new ConcurrentReaderHashMap();
-
       version = Version.instance();
       
       failoverStatusLock = new Object();
@@ -709,23 +696,6 @@
       return objectIDSequence++;
    }
 
-   public ServerConsumerEndpoint putConsumerEndpoint(int consumerID, ServerConsumerEndpoint c)
-   {
-      log.debug(this + " caching consumer " + consumerID);
-      return (ServerConsumerEndpoint)consumers.put(new Integer(consumerID), c);
-   }
-
-   public ServerConsumerEndpoint getConsumerEndpoint(int consumerID)
-   {
-      return (ServerConsumerEndpoint)consumers.get(new Integer(consumerID));
-   }
-
-   public ServerConsumerEndpoint removeConsumerEndpoint(Integer consumerID)
-   {
-      log.debug(this + " removing consumer " + consumerID + " from the cache");
-      return (ServerConsumerEndpoint)consumers.remove(consumerID);
-   }
-
    public QueuedExecutorPool getQueuedExecutorPool()
    {
       return queuedExecutorPool;

Added: trunk/src/main/org/jboss/jms/server/endpoint/Ack.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/Ack.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/Ack.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,36 @@
+/*
+ * 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.jms.server.endpoint;
+
+/**
+ * A Ack
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public interface Ack
+{
+   long getDeliveryId();
+}

Added: trunk/src/main/org/jboss/jms/server/endpoint/Cancel.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/Cancel.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/Cancel.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,105 @@
+/*
+  * 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.jms.server.endpoint;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+
+import org.jboss.messaging.util.Streamable;
+
+/**
+ * 
+ * A Cancel.
+ * 
+ * Used to send a cancel (NACK) to the server
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class Cancel implements Streamable
+{
+   // Constants -----------------------------------------------------
+   
+   // Attributes ----------------------------------------------------
+   
+   private long deliveryId;
+   
+   private int deliveryCount;      
+
+   // Static --------------------------------------------------------
+   
+   // Constructors --------------------------------------------------
+   
+   public Cancel()
+   {      
+   }
+   
+   public Cancel(long deliveryId, int deliveryCount)
+   {      
+      this.deliveryId = deliveryId;
+      
+      this.deliveryCount = deliveryCount;
+   }
+
+   // Public --------------------------------------------------------
+   
+   public long getDeliveryId()
+   {
+      return deliveryId;
+   }
+   
+   public int getDeliveryCount()
+   {
+      return deliveryCount;
+   }
+
+   // Streamable implementation -------------------------------------
+   
+   public void read(DataInputStream in) throws Exception
+   {
+      deliveryId = in.readLong();
+      
+      deliveryCount = in.readInt();
+   }
+
+   public void write(DataOutputStream out) throws Exception
+   {
+      out.writeLong(deliveryId);
+      
+      out.writeInt(deliveryCount);
+   }
+
+   // Class YYY overrides -------------------------------------------
+
+   // Protected -----------------------------------------------------
+
+   // Package Private -----------------------------------------------
+
+   // Private -------------------------------------------------------
+   
+   // Inner Classes -------------------------------------------------
+   
+}
+

Modified: trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ClientDelivery.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -37,6 +37,9 @@
  * A ClientDelivery
  * Encapsulates a delivery of some messages to a client consumer
  * 
+ * There is no need to specify the server id since the client side CallbackManager is
+ * unique to the remoting connection
+ * 
  * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
  * @version <tt>$Revision$</tt>
  *
@@ -53,10 +56,6 @@
    
    private List msgs;
          
-   //We need to specify the server id too since different servers might have the
-   //same consumer id
-   private int serverId;
-   
    private int consumerId;
     
    // Constructors --------------------------------------------------
@@ -65,12 +64,10 @@
    {      
    }
 
-   public ClientDelivery(List msgs, int serverId, int consumerId)
+   public ClientDelivery(List msgs, int consumerId)
    {
       this.msgs = msgs;
       
-      this.serverId = serverId;
-      
       this.consumerId = consumerId;
    }
   
@@ -79,8 +76,6 @@
    
    public void write(DataOutputStream out) throws Exception
    {
-      out.writeInt(serverId);
-      
       out.writeInt(consumerId);
       
       out.writeInt(msgs.size());
@@ -94,6 +89,8 @@
          out.writeByte(mp.getMessage().getType());
 
          out.writeInt(mp.getDeliveryCount());
+         
+         out.writeLong(mp.getDeliveryId());
 
          mp.getMessage().write(out);
       }      
@@ -101,8 +98,6 @@
 
    public void read(DataInputStream in) throws Exception
    {
-      serverId = in.readInt();
-      
       consumerId = in.readInt();
       
       int numMessages = in.readInt();
@@ -115,11 +110,13 @@
          
          int deliveryCount = in.readInt();
          
+         long deliveryId = in.readLong();
+         
          JBossMessage m = (JBossMessage)MessageFactory.createMessage(type);
 
          m.read(in);
 
-         MessageProxy md = JBossMessage.createThinDelegate(m, deliveryCount);
+         MessageProxy md = JBossMessage.createThinDelegate(deliveryId, m, deliveryCount);
          
          msgs.add(md);
       }      
@@ -132,11 +129,6 @@
       return msgs;
    }
    
-   public int getServerId()
-   {
-      return serverId;
-   }
-   
    public int getConsumerId()
    {
       return consumerId;

Added: trunk/src/main/org/jboss/jms/server/endpoint/DefaultAck.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/DefaultAck.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/DefaultAck.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,46 @@
+/*
+ * 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.jms.server.endpoint;
+
+/**
+ * A DefaultAck
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class DefaultAck implements Ack
+{
+   private long deliveryId;
+   
+   public DefaultAck(long deliveryId)
+   {
+      this.deliveryId = deliveryId;
+   }
+   
+   public long getDeliveryId()
+   {
+      return deliveryId;
+   }
+}

Added: trunk/src/main/org/jboss/jms/server/endpoint/DeliveryInfo.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/DeliveryInfo.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/DeliveryInfo.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,98 @@
+/*
+  * 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.jms.server.endpoint;
+
+import org.jboss.jms.message.MessageProxy;
+
+/**
+ * Struct like class for holding information regarding a delivery 
+ * on the client side - this is never passed to the server
+ * 
+ * @author <a href="mailto:tim.fox at jboss.com>Tim Fox </a>
+ * @author <a href="mailto:ovidiu at jboss.com>Ovidiu Feodorov</a>
+ *
+ * $Id: AckInfo.java 1770 2006-12-12 10:49:42Z timfox $
+ */
+public class DeliveryInfo implements Ack
+{
+   // Constants -----------------------------------------------------
+   
+   // Attributes ----------------------------------------------------
+   
+   //This is needed on failover when recreating delivery list on the server session
+   //we need to know the channel id so we can recreate the deliveries
+   private long channelID;
+   
+   //This is needed when doing local redelivery of messages, since we need to know which
+   //consumer gets the message
+   private int consumerId;      
+
+   private MessageProxy msg;
+   
+   // Static --------------------------------------------------------
+   
+   // Constructors --------------------------------------------------
+   
+
+   public DeliveryInfo(MessageProxy msg, int consumerId, long channelID)
+   {      
+      this.msg = msg;
+      
+      this.consumerId = consumerId;
+      
+      this.channelID = channelID;
+   }
+
+   // Public --------------------------------------------------------
+   
+   public long getChannelId()
+   {
+      return channelID;
+   }
+   
+   public int getConsumerId()
+   {
+      return consumerId;
+   }
+
+   public MessageProxy getMessageProxy()
+   {
+      return msg;
+   }
+   
+
+   // Ack Implementation  -------------------------------------------
+   
+   public long getDeliveryId()
+   {
+      return msg.getDeliveryId();
+   }
+
+   // Protected -----------------------------------------------------
+
+   // Package Private -----------------------------------------------
+
+   // Private -------------------------------------------------------
+   
+   // Inner Classes -------------------------------------------------
+   
+}

Added: trunk/src/main/org/jboss/jms/server/endpoint/DeliveryRecovery.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/DeliveryRecovery.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/DeliveryRecovery.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,94 @@
+/*
+ * 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.jms.server.endpoint;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+
+import org.jboss.messaging.util.Streamable;
+
+/**
+ * A DeliveryRecovery
+ * 
+ * Used for sending information about to recover a delivery to the server
+ * on failover
+ *
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ * @version <tt>$Revision: 1.1 $</tt>
+ *
+ * $Id$
+ *
+ */
+public class DeliveryRecovery implements Streamable
+{   
+   private long deliveryId;
+   
+   private long messageId;
+   
+   private long channelId;
+   
+   public DeliveryRecovery()
+   {      
+   }
+   
+   public DeliveryRecovery(long deliveryId, long messageId, long channelId)
+   {
+      this.deliveryId = deliveryId;
+      
+      this.messageId = messageId;
+      
+      this.channelId = channelId;
+   }
+   
+   public long getDeliveryId()
+   {
+      return deliveryId;
+   }
+   
+   public long getMessageId()
+   {
+      return messageId;
+   }
+   
+   public long getChannelId()
+   {
+      return channelId;
+   }
+
+   public void read(DataInputStream in) throws Exception
+   {
+      deliveryId = in.readLong();
+      
+      messageId = in.readLong();
+      
+      channelId = in.readLong();
+   }
+
+   public void write(DataOutputStream out) throws Exception
+   {
+      out.writeLong(deliveryId);
+      
+      out.writeLong(messageId);
+      
+      out.writeLong(channelId);
+   }
+}

Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerBrowserEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerBrowserEndpoint.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerBrowserEndpoint.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -30,6 +30,7 @@
 
 import org.jboss.jms.selector.Selector;
 import org.jboss.jms.server.remoting.JMSDispatcher;
+import org.jboss.jms.util.ExceptionUtil;
 import org.jboss.logging.Logger;
 import org.jboss.messaging.core.Channel;
 import org.jboss.messaging.core.Filter;
@@ -65,8 +66,8 @@
 
    // Constructors --------------------------------------------------
 
-   protected ServerBrowserEndpoint(ServerSessionEndpoint session, int id,
-                                   Channel destination, String messageSelector)
+   ServerBrowserEndpoint(ServerSessionEndpoint session, int id,
+                         Channel destination, String messageSelector)
       throws JMSException
    {     
       this.session = session;
@@ -87,24 +88,38 @@
 
    public boolean hasNextMessage() throws JMSException
    {
-      if (closed)
+      try
       {
-         throw new IllegalStateException("Browser is closed");
+         if (closed)
+         {
+            throw new IllegalStateException("Browser is closed");
+         }
+         return iterator.hasNext();
+      }   
+      catch (Throwable t)
+      {
+         throw ExceptionUtil.handleJMSInvocation(t, this + " hasNextMessage");
       }
-      return iterator.hasNext();
    }
    
    public Message nextMessage() throws JMSException
    {
-      if (closed)
+      try
       {
-         throw new IllegalStateException("Browser is closed");
+         if (closed)
+         {
+            throw new IllegalStateException("Browser is closed");
+         }
+         Routable r = (Routable)iterator.next();
+   
+         if (trace) { log.trace("returning the message corresponding to " + r); }
+         
+         return (Message)r.getMessage();
+      }   
+      catch (Throwable t)
+      {
+         throw ExceptionUtil.handleJMSInvocation(t, this + " nextMessage");
       }
-      Routable r = (Routable)iterator.next();
-
-      if (trace) { log.trace("returning the message corresponding to " + r); }
-      
-      return (Message)r.getMessage();
    }
    
    
@@ -112,52 +127,60 @@
 	//why not just pass back the arraylist??
    public Message[] nextMessageBlock(int maxMessages) throws JMSException
    {
-      if (closed)
+      try
       {
-         throw new IllegalStateException("Browser is closed");
-      }
-      
-      if (maxMessages < 2)
+         if (closed)
+         {
+            throw new IllegalStateException("Browser is closed");
+         }
+         
+         if (maxMessages < 2)
+         {
+            throw new IllegalArgumentException("maxMessages must be >=2 otherwise use nextMessage");
+         }
+         
+         ArrayList messages = new ArrayList(maxMessages);
+         int i = 0;
+         while (i < maxMessages)
+         {
+            if (iterator.hasNext())
+            {
+               Message m = (Message)((Routable)iterator.next()).getMessage();
+               messages.add(m);
+               i++;
+            }
+            else break;
+         }		
+   		return (Message[])messages.toArray(new Message[messages.size()]);	
+      }   
+      catch (Throwable t)
       {
-         throw new IllegalArgumentException("maxMessages must be >=2 otherwise use nextMessage");
+         throw ExceptionUtil.handleJMSInvocation(t, this + " nextMessageBlock");
       }
-      
-      ArrayList messages = new ArrayList(maxMessages);
-      int i = 0;
-      while (i < maxMessages)
-      {
-         if (iterator.hasNext())
-         {
-            Message m = (Message)((Routable)iterator.next()).getMessage();
-            messages.add(m);
-            i++;
-         }
-         else break;
-      }		
-		return (Message[])messages.toArray(new Message[messages.size()]);		        
    }
    
-   
    public void close() throws JMSException
    {
-      if (closed)
+      try
       {
-         throw new IllegalStateException("Browser is already closed");
+         localClose();
+         
+         session.removeBrowser(id);
+      }   
+      catch (Throwable t)
+      {
+         throw ExceptionUtil.handleJMSInvocation(t, this + " close");
       }
-      iterator = null;
-      session.removeBrowserDelegate(id);
-      JMSDispatcher.instance.unregisterTarget(new Integer(id));
-      closed = true;
    }
-   
+         
    public void closing() throws JMSException
    {
       // Do nothing
    }
-
-   public boolean isClosed()
+   
+   public boolean isClosed() throws JMSException
    {
-      return closed;
+      throw new IllegalStateException("isClosed should never be handled on the server side");
    }
 
    // Public --------------------------------------------------------
@@ -168,8 +191,22 @@
    }
 
    // Package protected ---------------------------------------------
+   
+   void localClose() throws JMSException
+   {
+      if (closed)
+      {
+         throw new IllegalStateException("Browser is already closed");
+      }
+      
+      iterator = null;
+      
+      JMSDispatcher.instance.unregisterTarget(new Integer(id));
+      
+      closed = true;
+   }
 
-   // Protected -----------------------------------------------------
+   // Protected -----------------------------------------------------      
 
    // Private -------------------------------------------------------
 

Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerConnectionEndpoint.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -21,6 +21,7 @@
   */
 package org.jboss.jms.server.endpoint;
 
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -44,9 +45,9 @@
 import org.jboss.jms.server.endpoint.advised.SessionAdvised;
 import org.jboss.jms.server.remoting.JMSDispatcher;
 import org.jboss.jms.server.remoting.JMSWireFormat;
-import org.jboss.jms.tx.AckInfo;
 import org.jboss.jms.tx.TransactionRequest;
-import org.jboss.jms.tx.TxState;
+import org.jboss.jms.tx.ClientTransaction;
+import org.jboss.jms.tx.ClientTransaction.SessionTxState;
 import org.jboss.jms.util.ExceptionUtil;
 import org.jboss.jms.util.ToString;
 import org.jboss.logging.Logger;
@@ -55,13 +56,9 @@
 import org.jboss.messaging.core.plugin.contract.PostOffice;
 import org.jboss.messaging.core.tx.Transaction;
 import org.jboss.messaging.core.tx.TransactionRepository;
-import org.jboss.messaging.util.ConcurrentReaderHashSet;
 import org.jboss.remoting.Client;
 import org.jboss.remoting.callback.ServerInvokerCallbackHandler;
-import org.jboss.util.id.GUID;
 
-import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
-
 /**
  * Concrete implementation of ConnectionEndpoint.
  * 
@@ -83,11 +80,11 @@
 
    private boolean trace = log.isTraceEnabled();
    
-   private boolean closed;
+   private volatile boolean closed;
    
    private volatile boolean started;
 
-   private int connectionID;
+   private int id;
    
    private String remotingClientSessionId;
    
@@ -124,11 +121,11 @@
    
    private int prefetchSize;
    
-   protected int defaultTempQueueFullSize;
+   private int defaultTempQueueFullSize;
    
-   protected int defaultTempQueuePageSize;
+   private int defaultTempQueuePageSize;
    
-   protected int defaultTempQueueDownCacheSize;
+   private int defaultTempQueueDownCacheSize;
 
    // Constructors --------------------------------------------------
    
@@ -148,7 +145,7 @@
  
       started = false;
 
-      this.connectionID = serverPeer.getNextObjectID();
+      this.id = serverPeer.getNextObjectID();
       this.clientID = clientID;
       this.prefetchSize = prefetchSize;
       
@@ -156,8 +153,8 @@
       this.defaultTempQueuePageSize = defaultTempQueuePageSize;
       this.defaultTempQueueDownCacheSize = defaultTempQueueDownCacheSize;
 
-      sessions = new ConcurrentReaderHashMap();
-      temporaryDestinations = new ConcurrentReaderHashSet();
+      sessions = new HashMap();
+      temporaryDestinations = new HashSet();
       
       this.username = username;
       this.password = password;
@@ -184,8 +181,14 @@
          // create the corresponding server-side session endpoint and register it with this
          // connection endpoint instance
          ServerSessionEndpoint ep = new ServerSessionEndpoint(sessionID, this);
-         putSessionDelegate(sessionID, ep);
+         
+         synchronized (sessions)
+         {
+            sessions.put(new Integer(sessionID), ep);
+         }
+         
          SessionAdvised sessionAdvised = new SessionAdvised(ep);
+         
          JMSDispatcher.instance.registerTarget(new Integer(sessionID), sessionAdvised);
 
          ClientSessionDelegate d = new ClientSessionDelegate(sessionID);
@@ -263,8 +266,10 @@
          {
             throw new IllegalStateException("Connection is closed");
          }
+         
          setStarted(false);
-         log.debug("Connection " + connectionID + " stopped");
+         
+         log.debug("Connection " + id + " stopped");
       }
       catch (Throwable t)
       {
@@ -284,43 +289,43 @@
             return;
          }
    
-         // We clone to avoid concurrent modification exceptions
-         for(Iterator i = new HashSet(sessions.values()).iterator(); i.hasNext(); )
+         synchronized (sessions)
          {
-            ServerSessionEndpoint sess = (ServerSessionEndpoint)i.next();
-   
-            // clear all consumers associated with this session from the serverPeer's cache
-            for(Iterator j = sess.getConsumerEndpointIDs().iterator(); j.hasNext(); )
+            for(Iterator i = sessions.values().iterator(); i.hasNext(); )
             {
-               Integer consumerID = (Integer)j.next();
-               serverPeer.removeConsumerEndpoint(consumerID);
+               ServerSessionEndpoint sess = (ServerSessionEndpoint)i.next();
+      
+               sess.localClose();
             }
-   
-            // ... and also close the session
-            sess.close();
+            
+            sessions.clear();
          }
          
-         for(Iterator i = temporaryDestinations.iterator(); i.hasNext(); )
+         synchronized (temporaryDestinations)
          {
-            JBossDestination dest = (JBossDestination)i.next();
-
-            if (dest.isQueue())
-            {     
-               postOffice.unbindQueue(dest.getName());               
-            }
-            else
+            for(Iterator i = temporaryDestinations.iterator(); i.hasNext(); )
             {
-               //No need to unbind - this will already have happened, and all removeAllReferences
-               //will have already been called when the subscriptions were closed
-               //which always happens before the connection closed (depth first close)              
+               JBossDestination dest = (JBossDestination)i.next();
+   
+               if (dest.isQueue())
+               {     
+                  postOffice.unbindQueue(dest.getName());               
+               }
+               else
+               {
+                  //No need to unbind - this will already have happened, and all removeAllReferences
+                  //will have already been called when the subscriptions were closed
+                  //which always happens before the connection closed (depth first close)              
+               }
             }
+            
+            temporaryDestinations.clear();
          }
-         
-         temporaryDestinations.clear();
    
          cm.unregisterConnection(jmsClientVMId, remotingClientSessionId);
    
-         JMSDispatcher.instance.unregisterTarget(new Integer(connectionID));
+         JMSDispatcher.instance.unregisterTarget(new Integer(id));
+         
          closed = true;
       }
       catch (Throwable t)
@@ -334,11 +339,6 @@
       log.trace(this + " closing (noop)");    
    }
 
-   public boolean isClosed()
-   {
-      return closed;
-   }
-
    public void sendTransaction(TransactionRequest request) throws JMSException
    {    
       try
@@ -407,6 +407,11 @@
          throw ExceptionUtil.handleJMSInvocation(t, this + " getPreparedTransactions");
       }
    }
+   
+   public boolean isClosed() throws JMSException
+   {
+      throw new IllegalStateException("isClosed should never be handled on the server side");
+   }
   
    // Public --------------------------------------------------------
    
@@ -468,132 +473,108 @@
       this.usingVersion = version;
    }
    
-   public byte getUsingVersion()
+   
+           
+   public String toString()
    {
+      return "ConnectionEndpoint[" + id + "]";
+   }
+
+   // Package protected ---------------------------------------------
+
+   byte getUsingVersion()
+   {
       return usingVersion;
    }
    
-   public int getPrefetchSize()
+   int getPrefetchSize()
    {
       return prefetchSize;
    }
    
-   public int getDefaultTempQueueFullSize()
+   int getDefaultTempQueueFullSize()
    {
       return defaultTempQueueFullSize;
    }
    
-   public int getDefaultTempQueuePageSize()
+   int getDefaultTempQueuePageSize()
    {
       return defaultTempQueuePageSize;
    }
      
-   public int getDefaultTempQueueDownCacheSize()
+   int getDefaultTempQueueDownCacheSize()
    {
       return defaultTempQueueDownCacheSize;
    }
-           
-   public String toString()
-   {
-      return "ConnectionEndpoint[" + connectionID + "]";
-   }
-
-   // Package protected ---------------------------------------------
-
    
-   // Protected -----------------------------------------------------
-   
-   protected ServerInvokerCallbackHandler getCallbackHandler()
+   ServerInvokerCallbackHandler getCallbackHandler()
    {
       return callbackHandler;
    }   
    
-   protected int getConnectionID()
+   int getConnectionID()
    {
-      return connectionID;
+      return id;
    }
    
-   protected boolean isStarted()
+   boolean isStarted()
    {
       return started;    
    }
    
-   /**
-    * Generates a sessionID that is unique per this ConnectionDelegate instance
-    */
-   protected String generateSessionID()
+   void removeSession(int sessionId) throws Exception
    {
-      return new GUID().toString();
+      synchronized (sessions)
+      {
+         if (sessions.remove(new Integer(sessionId)) == null)
+         {
+            throw new IllegalStateException("Cannot find session with id " + sessionId + " to remove");
+         }
+      }
    }
-      
-   protected ServerSessionEndpoint putSessionDelegate(int sessionID, ServerSessionEndpoint d)
-   {
-      return (ServerSessionEndpoint)sessions.put(new Integer(sessionID), d);
-   }
    
-   protected ServerSessionEndpoint getSessionDelegate(int sessionID)
+   void addTemporaryDestination(Destination dest)
    {
-      return (ServerSessionEndpoint)sessions.get(new Integer(sessionID));
+      synchronized (temporaryDestinations)
+      {
+         temporaryDestinations.add(dest);
+      }
    }
    
-   protected ServerSessionEndpoint removeSessionDelegate(int sessionID)
+   void removeTemporaryDestination(Destination dest)
    {
-      return (ServerSessionEndpoint)sessions.remove(new Integer(sessionID));
+      synchronized (temporaryDestinations)
+      {
+         temporaryDestinations.remove(dest);
+      }
    }
    
-   protected ServerConsumerEndpoint putConsumerEndpoint(int consumerID, ServerConsumerEndpoint c)
+   boolean hasTemporaryDestination(Destination dest)
    {
-      return serverPeer.putConsumerEndpoint(consumerID, c);
+      synchronized (temporaryDestinations)
+      {
+         return temporaryDestinations.contains(dest);
+      }
    }
    
-   protected ServerConsumerEndpoint getConsumerEndpoint(int consumerID)
+   ServerPeer getServerPeer()
    {
-      return serverPeer.getConsumerEndpoint(consumerID);
-   }
-   
-   protected ServerConsumerEndpoint removeConsumerEndpoint(Integer consumerID)
-   {
-      return serverPeer.removeConsumerEndpoint(consumerID);
-   }
-   
-   protected void addTemporaryDestination(Destination dest)
-   {
-      temporaryDestinations.add(dest);
-   }
-   
-   protected void removeTemporaryDestination(Destination dest)
-   {
-      temporaryDestinations.remove(dest);
-   }
-   
-   protected boolean hasTemporaryDestination(Destination dest)
-   {
-      return temporaryDestinations.contains(dest);
-   }
-   
-   protected ServerPeer getServerPeer()
-   {
       return serverPeer;
    }
    
-   protected String getRemotingClientSessionId()
+   String getRemotingClientSessionId()
    {
       return remotingClientSessionId;
    }
    
-   protected String getJmsClientVMId()
+   void sendMessage(JBossMessage msg, Transaction tx) throws Exception
    {
-      return jmsClientVMId;
-   }
-
-   protected void sendMessage(JBossMessage msg, Transaction tx) throws Exception
-   {
       JBossDestination dest = (JBossDestination)msg.getJMSDestination();
       
       // This allows the no-local consumers to filter out the messages that come from the same
       // connection
       // TODO Do we want to set this for ALL messages. Optimisation is possible here.
-      msg.setConnectionID(connectionID);
+      msg.setConnectionID(id);
       
       // We must reference the message *before* we send it the destination to be handled. This is
       // so we can guarantee that the message doesn't disappear from the store before the
@@ -628,7 +609,9 @@
          
       if (trace) { log.trace("sent " + msg); }
    }
-
+   
+   // Protected -----------------------------------------------------
+     
    // Private -------------------------------------------------------
    
    private void setStarted(boolean s) throws Throwable
@@ -638,46 +621,41 @@
          for (Iterator i = sessions.values().iterator(); i.hasNext(); )
          {
             ServerSessionEndpoint sd = (ServerSessionEndpoint)i.next();
+            
             sd.setStarted(s);
          }
          started = s;
       }
    }   
     
-   private void processTransaction(TxState txState, Transaction tx) throws Throwable
+   private void processTransaction(ClientTransaction txState, Transaction tx) throws Throwable
    {
-      if (trace) { log.trace("processing transaction, there are " + txState.getMessages().size() + " messages and " + txState.getAcks().size() + " acks "); }
+      if (trace) { log.trace("processing transaction"); }
       
-      for(Iterator i = txState.getMessages().iterator(); i.hasNext(); )
-      {
-         JBossMessage m = (JBossMessage)i.next();
-         
-         sendMessage(m, tx);
-      }
-      
-      if (trace) { log.trace("done the sends"); }
-      
-      // Then ack the acks
-      
-      List acks = txState.getAcks();
-      
-      // We create the transactional callbacks in reverse order so if the transaction is
-      // subsequently cancelled the refs are put back in the correct order on the queue/subscription
-      for (int i = acks.size() - 1; i >= 0; i--)
-      {      
-         AckInfo ack = (AckInfo)acks.get(i);
-         
-         ServerConsumerEndpoint consumer = getConsumerEndpoint(ack.getConsumerID());
-         if (consumer == null)
+      synchronized (sessions)
+      {         
+         for (Iterator i = txState.getSessionStates().iterator(); i.hasNext(); )
          {
-            throw new IllegalStateException("Cannot find consumer " + ack.getConsumerID());
+            SessionTxState sessionState = (SessionTxState)i.next();
+            
+            List msgs = sessionState.getMsgs();
+            
+            for (Iterator i2 = msgs.iterator(); i2.hasNext(); )
+            {
+               JBossMessage msg = (JBossMessage)i2.next();
+                     
+               sendMessage(msg, tx);
+            }
+                     
+            List acks = sessionState.getAcks();
+            
+            ServerSessionEndpoint session = (ServerSessionEndpoint)sessions.get(new Integer(sessionState.getSessionId()));
+            
+            session.acknowledgeTransactionally(acks, tx);      
          }
-         consumer.acknowledgeTransactionally(ack.getMessageID(), tx);
-         
-         if (trace) { log.trace("acked " + ack.getMessageID()); }
       }
       
-      if (trace) { log.trace("done the acks"); }
+      if (trace) { log.trace("Processed transaction"); }
    }   
 
    // Inner classes -------------------------------------------------

Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerConsumerEndpoint.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -23,10 +23,7 @@
 
 
 import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
 
 import javax.jms.IllegalStateException;
 import javax.jms.InvalidSelectorException;
@@ -46,15 +43,12 @@
 import org.jboss.messaging.core.Delivery;
 import org.jboss.messaging.core.DeliveryObserver;
 import org.jboss.messaging.core.MessageReference;
-import org.jboss.messaging.core.Queue;
 import org.jboss.messaging.core.Receiver;
 import org.jboss.messaging.core.Routable;
 import org.jboss.messaging.core.SimpleDelivery;
 import org.jboss.messaging.core.plugin.contract.PostOffice;
 import org.jboss.messaging.core.plugin.postoffice.Binding;
 import org.jboss.messaging.core.tx.Transaction;
-import org.jboss.messaging.core.tx.TransactionException;
-import org.jboss.messaging.core.tx.TxCallback;
 import org.jboss.messaging.util.Future;
 import org.jboss.remoting.callback.Callback;
 
@@ -113,28 +107,22 @@
    // No need to be volatile - is protected by lock
    private boolean closed;
 
-   // No need to be volatile
-   private boolean disconnected;
-
    private Executor executor;
 
    private int prefetchSize;
 
    private Object lock;
 
-   private Map deliveries;
-   
-   private Queue dlq;
-   
    private Object messagesInTransitLock;
+   
    private int messagesInTransitCount; // access only from a region guarded by messagesInTransitLock
    
    // Constructors --------------------------------------------------
 
-   protected ServerConsumerEndpoint(int id, Channel messageQueue, String queueName,
-                                    ServerSessionEndpoint sessionEndpoint,
-                                    String selector, boolean noLocal, JBossDestination dest,
-                                    int prefetchSize, Queue dlq)
+   ServerConsumerEndpoint(int id, Channel messageQueue, String queueName,
+                         ServerSessionEndpoint sessionEndpoint,
+                         String selector, boolean noLocal, JBossDestination dest,
+                         int prefetchSize)
       throws InvalidSelectorException
    {
       if (trace) { log.trace("constructing consumer endpoint " + id); }
@@ -144,8 +132,7 @@
       this.queueName = queueName;
       this.sessionEndpoint = sessionEndpoint;
       this.prefetchSize = prefetchSize;
-      this.dlq = dlq;
-
+      
       // We always created with clientConsumerFull = true. This prevents the SCD sending messages to
       // the client before the client has fully finished creating the MessageCallbackHandler.
       this.clientConsumerFull = true;
@@ -170,6 +157,7 @@
       // using the same queuedexecutor concurrently if there are a lot of active consumers.
 
       this.noLocal = noLocal;
+      
       this.destination = dest;
       
       this.toDeliver = new ArrayList();
@@ -182,24 +170,14 @@
          this.messageSelector = new Selector(selector);
          if (trace) log.trace("created selector");
       }
-
-      //TODO - 
-      //We really need to get rid of this delivery list - it's only purpose in life is to solve
-      //the race condition where acks or cancels can come in before handle has returned - and
-      //that can be solved in a simpler way anyway.
-      //It adds extra complexity both in all the extra code necessary to maintain it, the extra memory
-      //needed to maintain it, the extra complexity in synchronization on this class to protect access to it
-      //and when we do clustering we will have to replicate it too!!
-      //Let's GET RID OF IT!!!!!!!!!!!
-      this.deliveries = new LinkedHashMap();
-            
+       
       this.started = this.sessionEndpoint.getConnectionEndpoint().isStarted();
 
       // adding the consumer to the queue
       this.messageQueue.add(this);
       
       // prompt delivery
-      messageQueue.deliver(false);
+      promptDelivery();
 
       messagesInTransitLock = new Object();
       messagesInTransitCount = 0;
@@ -234,12 +212,6 @@
          // queue for delivery later.
          if (!started)
          {
-            // this is a common programming error, make this visible in the debug logs. However,
-            // make also possible to cut out the performance overhead for systems that raise the
-            // threshold to INFO or higher.
-
-            //TODO - Why was this debug
-            //log.isDebugEnabled is too slow!! especially on the primary execution path
             if (trace) { log.trace(this + " NOT started yet!"); }
 
             return null;
@@ -262,15 +234,15 @@
          {
             return delivery;
          }
+         
+         long deliveryId = sessionEndpoint.addDelivery(delivery);
 
-         deliveries.put(new Long(ref.getMessageID()), delivery);
-   
          // We don't send the message as-is, instead we create a MessageProxy instance. This allows
          // local fields such as deliveryCount to be handled by the proxy but global data to be
          // fielded by the same underlying Message instance. This allows us to avoid expensive
          // copying of messages
    
-         MessageProxy mp = JBossMessage.createThinDelegate(message, ref.getDeliveryCount());
+         MessageProxy mp = JBossMessage.createThinDelegate(deliveryId, message, ref.getDeliveryCount());
     
          // Add the proxy to the list to deliver
                            
@@ -319,9 +291,7 @@
          {
             int conId = ((JBossMessage)r).getConnectionID();
             
-            if (trace) { log.trace("message connection id: " + conId); }
-
-            if (trace) { log.trace("current connection connection id: " + sessionEndpoint.getConnectionEndpoint().getConnectionID()); }   
+            if (trace) { log.trace("message connection id: " + conId + " current connection connection id: " + sessionEndpoint.getConnectionEndpoint().getConnectionID()); }   
                  
             accept = conId != sessionEndpoint.getConnectionEndpoint().getConnectionID();
                 
@@ -352,56 +322,16 @@
    {      
       try
       {
-         synchronized (lock)
-         { 
-            // On close we only disconnect the consumer from the queue we don't actually remove
-            // it. This is because it may still contain deliveries that may well be acknowledged
-            // after the consumer has closed. This is perfectly valid.
-
-            // TODO - The deliveries should really be stored in the session endpoint, not here
-            // that is their natural place, that would mean we wouldn't have to mess around with
-            // keeping deliveries after this is closed.
-
-            if (trace) { log.trace(this + " grabbed the main lock in close()"); }
-
-            disconnect(); 
-            
-            JMSDispatcher.instance.unregisterTarget(new Integer(id));
-            
-            // If this is a consumer of a non durable subscription then we want to unbind the
-            // subscription and delete all its data.
-
-            if (destination.isTopic())
-            {
-               PostOffice postOffice = 
-                  sessionEndpoint.getConnectionEndpoint().getServerPeer().getPostOfficeInstance();
-               
-               Binding binding = postOffice.getBindingForQueueName(queueName);
-
-               //Note binding can be null since there can many competing subscribers for the subscription  - 
-               //in which case the first will have removed the subscription and subsequently
-               //ones won't find it
-               
-               if (binding != null && !binding.getQueue().isRecoverable())
-               {
-                  postOffice.unbindQueue(queueName);
-               }
-            }
-                        
-            closed = true;
-         }
-      }
+         localClose();
+         
+         sessionEndpoint.removeConsumer(id);
+      }   
       catch (Throwable t)
       {
          throw ExceptionUtil.handleJMSInvocation(t, this + " close");
       }
    }
-
-   public boolean isClosed()
-   {
-      return closed;
-   }
-               
+           
    // ConsumerEndpoint implementation -------------------------------
    
    /*
@@ -475,6 +405,11 @@
          messagesInTransitLock.notifyAll();
       }
    }
+   
+   public boolean isClosed() throws JMSException
+   {
+      throw new IllegalStateException("isClosed should never be handled on the server side");
+   }
 
    // Public --------------------------------------------------------
    
@@ -493,188 +428,43 @@
       return sessionEndpoint;
    }
    
-   public int getId()
-   {
-      return id;
-   }
-    
    // Package protected ---------------------------------------------
    
-   // Protected -----------------------------------------------------   
-   
-   protected void acknowledgeTransactionally(long messageID, Transaction tx) throws Throwable
-   {
-      if (trace) { log.trace("acknowledging transactionally " + messageID); }
-      
-      Delivery d = null;
-                 
-      // The actual removal of the deliveries from the delivery list is deferred until tx commit
+   void localClose() throws Throwable
+   {      
       synchronized (lock)
-      {
-         d = (Delivery)deliveries.get(new Long(messageID));
-      }
-      
-      DeliveryCallback deliveryCallback = (DeliveryCallback)tx.getCallback(this);
-            
-      if (deliveryCallback == null)
-      {
-         deliveryCallback = new DeliveryCallback();
-         tx.addCallback(deliveryCallback, this);
-      }
-      deliveryCallback.addMessageID(messageID);
+      { 
+         if (trace) { log.trace(this + " grabbed the main lock in close() " + this); }
+
+         messageQueue.remove(this); 
          
-      if (d != null)
-      {
-         d.acknowledge(tx);
-      }
-      else
-      {
-         //throw new IllegalStateException("Could not find delivery to acknowledge");
-         //TODO - Reenable this exception
-         log.warn("Coud not find acknowledge... Exception disabled for tests.. please re-enable before merging into trunk");
-      }             
-   }      
-   
-   protected void acknowledge(long messageID) throws Throwable
-   {  
-      // acknowledge a delivery   
-      Delivery d;
-      
-      synchronized (lock)
-      {
-         d = (Delivery)deliveries.remove(new Long(messageID));
-      }
-      
-      if (d != null)
-      {
-         d.acknowledge(null);
-      }
-      else
-      {     
-         throw new IllegalStateException("Cannot find delivery to acknowledge:" + messageID);
-      }      
-   }
-   
-   /**
-    * Actually remove the consumer and clear up any deliveries it may have
-    * This is called by the session on session.close()
-    * We can get rid of this when we store the deliveries on the session
-    *
-    **/
-   protected void remove() throws Throwable
-   {         
-      if (trace) log.trace("attempting to remove receiver " + this + " from destination " + messageQueue);
-      
-      boolean wereDeliveries = false;
-      for(Iterator i = deliveries.values().iterator(); i.hasNext(); )
-      {
+         JMSDispatcher.instance.unregisterTarget(new Integer(id));
+         
+         // If this is a consumer of a non durable subscription then we want to unbind the
+         // subscription and delete all its data.
 
-         Delivery d = (Delivery)i.next();
-
-         d.cancel();
-         wereDeliveries = true;
-      }
-      deliveries.clear();           
-      
-      if (!disconnected)
-      {
-         if (!closed)
+         if (destination.isTopic())
          {
-            close();
-         }
-      }
-      
-      sessionEndpoint.getConnectionEndpoint().
-         getServerPeer().removeConsumerEndpoint(new Integer(id));                  
+            PostOffice postOffice = 
+               sessionEndpoint.getConnectionEndpoint().getServerPeer().getPostOfficeInstance();
             
-      sessionEndpoint.removeConsumerEndpoint(id);
-      
-      if (wereDeliveries)
-      {
-         //If we cancelled any deliveries we need to force a deliver on the queue
-         //This is because there may be other waiting competing consumers who need a chance to get
-         //any of the cancelled messages
-         messageQueue.deliver(false);
-      }
-   }  
-   
-   protected void promptDelivery()
-   {
-      messageQueue.deliver(false);
-   }
-   
-   protected void sendToDLQ(Long messageID, Transaction tx) throws Throwable
-   {
-      Delivery del = (Delivery)deliveries.remove(messageID);
-      
-      if (del != null)
-      { 
-         log.warn(del.getReference() + " has exceed maximum delivery attempts and will be sent to the DLQ");
-         
-         if (dlq != null)
-         {         
-            //reset delivery count to zero
-            del.getReference().setDeliveryCount(0);
-            
-            dlq.handle(null, del.getReference(), tx);
-            
-            del.acknowledge(tx);           
-         }
-         else
-         {
-            log.warn("Cannot send to DLQ since DLQ has not been deployed! The message will be removed");
-            
-            del.acknowledge(tx);
-         }
-      }
-      else
-      {
-         throw new IllegalStateException("Cannot find delivery to send to DLQ:" + id);
-      }
-      
-   }
+            Binding binding = postOffice.getBindingForQueueName(queueName);
 
-   protected void createDeliveries(List messageIds) throws Throwable
-   {
-      List dels = messageQueue.createDeliveries(messageIds);
+            //Note binding can be null since there can many competing subscribers for the subscription  - 
+            //in which case the first will have removed the subscription and subsequently
+            //ones won't find it
             
-      synchronized (lock)
-      {      
-         Iterator iter = dels.iterator();
-         
-         while (iter.hasNext())
-         {
-            Delivery del = (Delivery)iter.next();
-            
-            deliveries.put(new Long(del.getReference().getMessageID()), del);
+            if (binding != null && !binding.getQueue().isRecoverable())
+            {
+               postOffice.unbindQueue(queueName);
+            }
          }
+                     
+         closed = true;
       }
-      
-      //Prompt delivery
-      messageQueue.deliver(false);
-   }
-
-   protected void cancelDelivery(Long messageID, int deliveryCount) throws Throwable
-   {
-      Delivery del = (Delivery)deliveries.remove(messageID);
-      
-      if (del != null)
-      {                               
-         //Cancel back to the queue
-         
-         //Update the delivery count
+   }        
            
-         del.getReference().setDeliveryCount(deliveryCount);
-              
-         del.cancel();         
-      }
-      else
-      {
-         throw new IllegalStateException("Cannot find delivery to cancel:" + id);
-      }
-   }
-           
-   protected void start()
+   void start()
    {             
       synchronized (lock)
       {
@@ -693,10 +483,10 @@
       }
       
       // Prompt delivery
-      messageQueue.deliver(false);
+      promptDelivery();
    }
    
-   protected void stop() throws Throwable
+   void stop() throws Throwable
    {     
       // We need to:
       // - Stop accepting any new messages in the SCE.
@@ -707,8 +497,7 @@
       // already executing and messages might get deposited after.
       synchronized (lock)
       {
-         // can't start or stop it if it is closed
-         if (closed)
+         if (!started)
          {
             return;
          }
@@ -762,36 +551,35 @@
       { 
          synchronized (lock)
          {
+            //Cancel in reverse order
             for (int i = toDeliver.size() - 1; i >= 0; i--)
             {
                MessageProxy proxy = (MessageProxy)toDeliver.get(i);
-               long id = proxy.getMessage().getMessageID();
-               cancelDelivery(new Long(id), proxy.getMessage().getDeliveryCount());
+
+               sessionEndpoint.cancelDelivery(proxy.getDeliveryId());
             }
          }
                  
          toDeliver.clear();
+         
          bufferFull = false;
       }      
+      
+      //Need to prompt delivery
+      promptDelivery();
    }
+   
+   
+   
+   // Protected -----------------------------------------------------         
       
    // Private -------------------------------------------------------
    
-   /**
-    * Disconnect this consumer from the queue that feeds it. This method does not clear up
-    * deliveries
-    */
-   private void disconnect()
+   private void promptDelivery()
    {
-      boolean removed = messageQueue.remove(this);
-      
-      if (removed)
-      {
-         disconnected = true;
-         if (trace) { log.trace(this + " removed from the queue"); }
-      }
+      messageQueue.deliver(false);
    }
-
+   
    // Inner classes -------------------------------------------------   
    
    /*
@@ -835,12 +623,7 @@
          ServerConnectionEndpoint connection =
             ServerConsumerEndpoint.this.sessionEndpoint.getConnectionEndpoint();
          
-         int serverId = connection.getServerPeer().getServerPeerID();
-
-         // TODO How can we ensure that messages for the same consumer aren't delivered
-         // concurrently to the same consumer on different threads?
-
-         ClientDelivery del = new ClientDelivery(list, serverId, id);
+         ClientDelivery del = new ClientDelivery(list, id);
          MessagingMarshallable mm = new MessagingMarshallable(connection.getUsingVersion(), del);
          Callback callback = new Callback(mm);
 
@@ -902,63 +685,5 @@
       {
          result.setResult(null);
       }
-   }
-   
-   /**
-    * 
-    * The purpose of this class is to remove deliveries from the delivery list on commit
-    * Each transaction has once instance of this per SCE
-    *
-    */
-   private class DeliveryCallback implements TxCallback
-   {
-      List delList = new ArrayList();
-         
-      public void beforePrepare()
-      {         
-         //NOOP
-      }
-      
-      public void beforeCommit(boolean onePhase)
-      {         
-         //NOOP
-      }
-      
-      public void beforeRollback(boolean onePhase)
-      {         
-         //NOOP
-      }
-      
-      public void afterPrepare()
-      {         
-         //NOOP
-      }
-      
-      public synchronized void afterCommit(boolean onePhase) throws TransactionException
-      {
-         // Remove the deliveries from the delivery map.
-         Iterator iter = delList.iterator();
-         while (iter.hasNext())
-         {
-            Long messageID = (Long)iter.next();
-            
-            if (deliveries.remove(messageID) == null)
-            {
-               //throw new TransactionException("Failed to remove delivery " + messageID);
-               log.warn("Couldn't remove delivery " + messageID + "- reenable exception before merging into trunk");
-               //TODO reenable exception
-            }
-         }
-      }
-      
-      public void afterRollback(boolean onePhase) throws TransactionException
-      {                            
-         //NOOP
-      }
-      
-      synchronized void addMessageID(long messageID)
-      {
-         delList.add(new Long(messageID));
-      }
-   }
+   }   
 }

Modified: trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -24,11 +24,11 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -56,11 +56,12 @@
 import org.jboss.jms.server.endpoint.advised.BrowserAdvised;
 import org.jboss.jms.server.endpoint.advised.ConsumerAdvised;
 import org.jboss.jms.server.remoting.JMSDispatcher;
-import org.jboss.jms.tx.AckInfo;
 import org.jboss.jms.util.ExceptionUtil;
 import org.jboss.jms.util.MessageQueueNameHelper;
 import org.jboss.logging.Logger;
+import org.jboss.messaging.core.Channel;
 import org.jboss.messaging.core.Delivery;
+import org.jboss.messaging.core.DeliveryObserver;
 import org.jboss.messaging.core.Queue;
 import org.jboss.messaging.core.local.PagingFilteredQueue;
 import org.jboss.messaging.core.plugin.IdManager;
@@ -72,10 +73,14 @@
 import org.jboss.messaging.core.plugin.postoffice.cluster.LocalClusteredQueue;
 import org.jboss.messaging.core.plugin.postoffice.cluster.RemoteQueueStub;
 import org.jboss.messaging.core.tx.Transaction;
+import org.jboss.messaging.core.tx.TransactionException;
 import org.jboss.messaging.core.tx.TransactionRepository;
+import org.jboss.messaging.core.tx.TxCallback;
 import org.jboss.util.id.GUID;
 
+import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
 import EDU.oswego.cs.dl.util.concurrent.QueuedExecutor;
+import EDU.oswego.cs.dl.util.concurrent.SynchronizedLong;
 
 /**
  * Concrete implementation of SessionEndpoint.
@@ -99,9 +104,9 @@
 
    private boolean trace = log.isTraceEnabled();
 
-   private int sessionID;
+   private int id;
 
-   private boolean closed;
+   private volatile boolean closed;
 
    private ServerConnectionEndpoint connectionEndpoint;
 
@@ -120,12 +125,18 @@
    private int maxDeliveryAttempts;
    private Queue dlq;
    
+   // Map < deliveryId, Delivery>
+   private Map deliveries;
+   
+   private SynchronizedLong deliveryIdSequence;
+   
+   
    // Constructors --------------------------------------------------
 
-   protected ServerSessionEndpoint(int sessionID, ServerConnectionEndpoint connectionEndpoint)
+   ServerSessionEndpoint(int sessionID, ServerConnectionEndpoint connectionEndpoint)
       throws Exception
    {
-      this.sessionID = sessionID;
+      this.id = sessionID;
 
       this.connectionEndpoint = connectionEndpoint;
 
@@ -146,7 +157,10 @@
       dlq = sp.getDLQ();
       tr = sp.getTxRepository();
       maxDeliveryAttempts = sp.getMaxDeliveryAttempts();
-
+      
+      deliveries = new ConcurrentHashMap();
+      
+      deliveryIdSequence = new SynchronizedLong(0);
    }
    
    // SessionDelegate implementation --------------------------------
@@ -213,7 +227,11 @@
    	   ServerBrowserEndpoint ep =
    	      new ServerBrowserEndpoint(this, browserID, (PagingFilteredQueue)binding.getQueue(), messageSelector);
    	   
-   	   putBrowserDelegate(browserID, ep);
+         //Still need to synchronized since close() can come in on a different thread
+         synchronized (browsers)
+         {
+            browsers.put(new Integer(browserID), ep);
+         }
    	   
          JMSDispatcher.instance.registerTarget(new Integer(browserID), new BrowserAdvised(ep));
    	   
@@ -276,49 +294,27 @@
          throw ExceptionUtil.handleJMSInvocation(t, this + " createTopic");
       }
    }
-
+   
    public void close() throws JMSException
    {
       try
       {
-         if (closed)
-         {
-            throw new IllegalStateException("Session is already closed");
-         }
+         localClose();
          
-         if (trace) log.trace(this + " close()");
-               
-         // clone to avoid ConcurrentModificationException
-         HashSet consumerSet = new HashSet(consumers.values());
-         
-         for(Iterator i = consumerSet.iterator(); i.hasNext(); )
-         {
-            ((ServerConsumerEndpoint)i.next()).remove();
-         }           
-         
-         connectionEndpoint.removeSessionDelegate(sessionID);
-         
-         JMSDispatcher.instance.unregisterTarget(new Integer(sessionID));
-         
-         closed = true;
+         connectionEndpoint.removeSession(id);
       }
       catch (Throwable t)
       {
          throw ExceptionUtil.handleJMSInvocation(t, this + " close");
       }
    }
-   
+      
    public void closing() throws JMSException
    {
       // currently does nothing
       if (trace) log.trace(this + " closing (noop)");
    }
-
-   public boolean isClosed()
-   {
-      return closed;
-   }
-   
+ 
    public void send(JBossMessage message) throws JMSException
    {
       try
@@ -331,17 +327,24 @@
       }
    }
    
-   public void acknowledgeBatch(List ackInfos) throws JMSException
+   public void acknowledgeBatch(List acks) throws JMSException
    {      
       try
       {
-         Iterator iter = ackInfos.iterator();
+         Iterator iter = acks.iterator();
          
          while (iter.hasNext())
          {
-            AckInfo ackInfo = (AckInfo)iter.next();
+            Ack ack = (Ack)iter.next();
             
-            acknowledgeInternal(ackInfo);
+            Delivery del = (Delivery)deliveries.remove(new Long(ack.getDeliveryId()));
+            
+            if (del == null)
+            {
+               throw new IllegalStateException("Cannot find delivery to acknowledge: " + ack.getDeliveryId());
+            }
+            
+            del.acknowledge(null);
          }
       }
       catch (Throwable t)
@@ -350,56 +353,63 @@
       }
    }
    
-   public void acknowledge(AckInfo ackInfo) throws JMSException
+   public void acknowledge(Ack ack) throws JMSException
    {
       try
       {
-         acknowledgeInternal(ackInfo);      
+         Delivery del = (Delivery)deliveries.remove(new Long(ack.getDeliveryId()));
+         
+         if (del == null)
+         {
+            throw new IllegalStateException("Cannot find delivery to acknowledge: " + ack.getDeliveryId());
+         }
+         
+         del.acknowledge(null);    
       }
       catch (Throwable t)
       {
          throw ExceptionUtil.handleJMSInvocation(t, this + " acknowledge");
       }
-   }
+   }     
 
-   public void cancelDeliveries(List ackInfos) throws JMSException
+   public void cancelDeliveries(List cancels) throws JMSException
    {
       try
       {
          // deliveries must be cancelled in reverse order
-          
-         Set consumers = new HashSet();
-         
+           
          List forDLQ = null;
          
-         for (int i = ackInfos.size() - 1; i >= 0; i--)
+         Set channels = new HashSet();
+                           
+         for (int i = cancels.size() - 1; i >= 0; i--)
          {
-            AckInfo ack = (AckInfo)ackInfos.get(i);
+            Cancel cancel = (Cancel)cancels.get(i);
             
-            // We look in the global map since the message might have come from connection consumer
-            ServerConsumerEndpoint consumer =
-               this.connectionEndpoint.getConsumerEndpoint(ack.getConsumerID());
-   
-            if (consumer == null)
+            Delivery del = (Delivery)deliveries.remove(new Long(cancel.getDeliveryId()));
+            
+            if (del == null)
             {
-               throw new IllegalArgumentException("Cannot find consumer id: " + ack.getConsumerID());
+               throw new IllegalStateException("Cannot find delivery to cancel " + cancel.getDeliveryId());
             }
-            
-            if (ack.getDeliveryCount() >= maxDeliveryAttempts)
+                                    
+            if (cancel.getDeliveryCount() >= maxDeliveryAttempts)
             {
                if (forDLQ == null)
                {
                   forDLQ = new ArrayList();
                }
                
-               forDLQ.add(ack);
+               forDLQ.add(del);
             }
             else
-            {            
-               consumer.cancelDelivery(new Long(ack.getMessageID()), ack.getDeliveryCount());
+            {                                                   
+               del.getReference().setDeliveryCount(cancel.getDeliveryCount());
+               
+               del.cancel();
+               
+               channels.add(del.getObserver());
             }
-            
-            consumers.add(consumer);
          }
          
          //Send stuff to DLQ
@@ -414,17 +424,23 @@
             {               
                for (int i = forDLQ.size() - 1; i >= 0; i--)
                {
-                  AckInfo ack = (AckInfo)forDLQ.get(i);
+                  Delivery del = (Delivery)forDLQ.get(i);
                   
-                  ServerConsumerEndpoint consumer =
-                     this.connectionEndpoint.getConsumerEndpoint(ack.getConsumerID());
-         
-                  if (consumer == null)
+                  if (dlq != null)
+                  {         
+                     //reset delivery count to zero
+                     del.getReference().setDeliveryCount(0);
+                     
+                     dlq.handle(null, del.getReference(), tx);
+                     
+                     del.acknowledge(tx);           
+                  }
+                  else
                   {
-                     throw new IllegalArgumentException("Cannot find consumer id: " + ack.getConsumerID());
-                  }
-                  
-                  consumer.sendToDLQ(new Long(ack.getMessageID()), tx);                              
+                     log.warn("Cannot send to DLQ since DLQ has not been deployed! The message will be removed");
+                     
+                     del.acknowledge(tx);
+                  }                              
                }
                
                tx.commit();
@@ -437,49 +453,49 @@
             }
          }
          
-         // need to prompt delivery for all consumers
+         // need to prompt delivery for all affected channels
          
-         for(Iterator i = consumers.iterator(); i.hasNext(); )
-         {
-            ServerConsumerEndpoint consumer = (ServerConsumerEndpoint)i.next();
-            consumer.promptDelivery();
-         }
+         promptDelivery(channels);
       }
       catch (Throwable t)
       {
          throw ExceptionUtil.handleJMSInvocation(t, this + " cancelDeliveries");
       }
-   }
+   }         
    
-   public void sendUnackedAckInfos(List ackInfos) throws JMSException
+   public void recoverDeliveries(List deliveryRecoveryInfos) throws JMSException
    {
+      if (trace) { log.trace(this + "recoverDeliveries(): " + deliveryRecoveryInfos); }
       try
       {
-         //Sort into different list for each consumer
+         if (postOffice.isLocal())
+         {
+            throw new IllegalStateException("Recovering deliveries but post office is not clustered!");
+         }
+         
+         ClusteredPostOffice po = (ClusteredPostOffice)postOffice;
+         
+         long maxDeliveryId = 0;
+                  
+         //Sort into different list for each channel
          Map ackMap = new HashMap();
                   
-         for (int i = ackInfos.size() - 1; i >= 0; i--)
+         for (Iterator iter = deliveryRecoveryInfos.iterator(); iter.hasNext(); )
          {
-            AckInfo ack = (AckInfo)ackInfos.get(i);
+            DeliveryRecovery deliveryInfo = (DeliveryRecovery)iter.next();
+                
+            Long channelId = new Long(deliveryInfo.getChannelId());
             
-            ServerConsumerEndpoint consumer =
-               this.connectionEndpoint.getConsumerEndpoint(ack.getConsumerID());
-   
-            if (consumer == null)
-            {
-               throw new IllegalArgumentException("Cannot find consumer id: " + ack.getConsumerID());
-            }
+            List acks = (List)ackMap.get(channelId);
             
-            LinkedList acks = (LinkedList)ackMap.get(consumer);
-            
             if (acks == null)
             {
-               acks = new LinkedList();
+               acks = new ArrayList();
                
-               ackMap.put(consumer, acks);
+               ackMap.put(channelId, acks);
             }
             
-            acks.addFirst(new Long(ack.getMessageID()));
+            acks.add(deliveryInfo);
          }  
          
          Iterator iter = ackMap.entrySet().iterator();
@@ -488,19 +504,59 @@
          {
             Map.Entry entry = (Map.Entry)iter.next();
             
-            ServerConsumerEndpoint consumer = (ServerConsumerEndpoint)entry.getKey();
+            Long channelId = (Long)entry.getKey();
             
+            //Look up channel
+            Binding binding = po.getBindingforChannelId(channelId.longValue());
+            
+            if (binding == null)
+            {
+               throw new IllegalStateException("Cannot find channel with id: " + channelId);
+            }
+            
             List acks = (List)entry.getValue();
             
-            consumer.createDeliveries(acks);
+            List ids = new ArrayList(acks.size());
+            
+            for (Iterator iter2 = acks.iterator(); iter2.hasNext(); )
+            {
+               DeliveryRecovery info = (DeliveryRecovery)iter2.next();
+               
+               ids.add(new Long(info.getMessageId()));
+            }
+            
+            Queue queue = binding.getQueue();
+            
+            List dels = queue.createDeliveries(ids);
+            
+            Iterator iter2 = dels.iterator();
+            
+            Iterator iter3 = acks.iterator();
+            
+            while (iter2.hasNext())
+            {
+               Delivery del = (Delivery)iter2.next();
+               
+               DeliveryRecovery info = (DeliveryRecovery)iter3.next();
+               
+               long deliveryId = info.getDeliveryId();
+               
+               maxDeliveryId = Math.max(maxDeliveryId, deliveryId);
+               
+               if (trace) { log.trace(this + " Recovered delivery " + deliveryId + ", " + del); }
+               
+               deliveries.put(new Long(deliveryId), del);
+            }
          }
+         
+         this.deliveryIdSequence = new SynchronizedLong(maxDeliveryId + 1);
       }
       catch (Throwable t)
       {
-         throw ExceptionUtil.handleJMSInvocation(t, this + " sendUnackedAckInfos");
+         throw ExceptionUtil.handleJMSInvocation(t, this + " recoverDeliveries");
       }
    }
-
+   
    public void addTemporaryDestination(JBossDestination dest) throws JMSException
    {
       try
@@ -670,6 +726,11 @@
          throw ExceptionUtil.handleJMSInvocation(t, this + " unsubscribe");
       }
    }
+   
+   public boolean isClosed() throws JMSException
+   {
+      throw new IllegalStateException("isClosed should never be handled on the server side");
+   }
     
    // Public --------------------------------------------------------
    
@@ -680,57 +741,184 @@
 
    public String toString()
    {
-      return "SessionEndpoint[" + sessionID + "]";
+      return "SessionEndpoint[" + id + "]";
    }
 
    // Package protected ---------------------------------------------
-
-   /**
-    * @return a Set<Integer>
-    */
-   Set getConsumerEndpointIDs()
+   
+   void removeBrowser(int browserId) throws Exception
    {
-      return consumers.keySet();
+      synchronized (browsers)
+      {
+         if (browsers.remove(new Integer(browserId)) == null)
+         {
+            throw new IllegalStateException("Cannot find browser with id " + browserId + " to remove");
+         }
+      }
    }
    
-   // Protected -----------------------------------------------------
-      
-   protected ServerConsumerEndpoint putConsumerEndpoint(int consumerID, ServerConsumerEndpoint d)
+   void removeConsumer(int consumerId) throws Exception
    {
-      if (trace) { log.trace(this + " caching consumer " + consumerID); }
-      return (ServerConsumerEndpoint)consumers.put(new Integer(consumerID), d);
+      synchronized (consumers)
+      {
+         if (consumers.remove(new Integer(consumerId)) == null)
+         {
+            throw new IllegalStateException("Cannot find consumer with id " + consumerId + " to remove");
+         }
+      }
    }
+   
+//   void promptDeliveryOnConsumers()
+//   {
+//      if (trace) { log.trace(this + " promptDeliveryOnConsumers(), there are " + consumers.size() + " consumers"); }
+//      synchronized (consumers)
+//      {         
+//         for (Iterator i = consumers.values().iterator(); i.hasNext(); )
+//         {
+//            ServerConsumerEndpoint consumer = (ServerConsumerEndpoint)i.next();
+//            
+//            consumer.promptDelivery();
+//         }
+//      }
+//   }
+   
+   void localClose() throws Throwable
+   {
+      if (closed)
+      {
+         throw new IllegalStateException("Session is already closed");
+      }
+      
+      if (trace) log.trace(this + " close()");
+            
+      synchronized (consumers)
+      {            
+         for( Iterator i = consumers.values().iterator(); i.hasNext(); )
+         {
+            ((ServerConsumerEndpoint)i.next()).localClose();
+         }  
+         
+         consumers.clear();
+      }
+      
+      synchronized (browsers)
+      {            
+         for( Iterator i = browsers.values().iterator(); i.hasNext(); )
+         {
+            ((ServerBrowserEndpoint)i.next()).localClose();
+         }  
+         
+         browsers.clear();
+      }
+      
+      //Now cancel any remaining deliveries in reverse delivery order
+      //Note we don't maintain order using a LinkedHashMap since then we lose
+      //concurrency since we would have to lock it exclusively
+      
+      List entries = new ArrayList(deliveries.entrySet());
+      
+      //Sort them in reverse delivery id order
+      Collections.sort(entries,
+                       new Comparator()
+                       {
+                           public int compare(Object obj1, Object obj2)
+                           {
+                              Map.Entry entry1 = (Map.Entry)obj1;
+                              Map.Entry entry2 = (Map.Entry)obj2;
+                              Long id1 = (Long)entry1.getKey();
+                              Long id2 = (Long)entry2.getKey();
+                              return id2.compareTo(id1);
+                           } 
+                       });
 
-   protected ServerConsumerEndpoint getConsumerEndpoint(int consumerID)
-   {
-      return (ServerConsumerEndpoint)consumers.get(new Integer(consumerID));
-   }
+      Iterator iter = entries.iterator();
+            
+      Set channels = new HashSet();
+      
+      if (trace) { log.trace("Cancelling " + entries.size() + " deliveries"); }
+      
+      while (iter.hasNext())
+      {
+         Map.Entry entry = (Map.Entry)iter.next();
+         
+         if (trace) { log.trace("Cancelling delivery with delivery id: " + entry.getKey()); }
+         
+         Delivery del = (Delivery)entry.getValue();
+         
+         del.cancel();
+         
+         channels.add(del.getObserver());
+      }
+      
+      promptDelivery(channels);
+      
+      deliveries.clear();
+            
+      JMSDispatcher.instance.unregisterTarget(new Integer(id));
+      
+      closed = true;
+   }            
    
-   protected ServerConsumerEndpoint removeConsumerEndpoint(int consumerID)
+   void cancelDelivery(long deliveryId) throws Throwable
    {
-      if (trace) { log.trace(this + " removing consumer " + consumerID + " from cache"); }
-      return (ServerConsumerEndpoint)consumers.remove(new Integer(consumerID));
+      Delivery del = (Delivery)deliveries.remove(new Long(deliveryId));
+      
+      if (del == null)
+      {
+         throw new IllegalStateException("Cannot find delivery to cancel " + deliveryId);
+      }
+      
+      del.cancel();
    }
    
-   protected ServerBrowserEndpoint putBrowserDelegate(int browserID, ServerBrowserEndpoint sbd)
+   long addDelivery(Delivery del)
    {
-      return (ServerBrowserEndpoint)browsers.put(new Integer(browserID), sbd);
+      long deliveryId = deliveryIdSequence.increment();
+      
+      deliveries.put(new Long(deliveryId), del);
+      
+      if (trace) { log.trace(this + " Added delivery: " + deliveryId + ", " + del); }
+      
+      return deliveryId;      
    }
    
-   protected ServerBrowserEndpoint getBrowserDelegate(int browserID)
+   void acknowledgeTransactionally(List acks, Transaction tx) throws Throwable
    {
-      return (ServerBrowserEndpoint)browsers.get(new Integer(browserID));
+      if (trace) { log.trace("Acknowledging transactionally " + acks.size() + " for tx: " + tx); }
+      
+      DeliveryCallback deliveryCallback = (DeliveryCallback)tx.getCallback(this);
+      
+      if (deliveryCallback == null)
+      {
+         deliveryCallback = new DeliveryCallback();
+         tx.addCallback(deliveryCallback, this);
+      }
+            
+      Iterator iter = acks.iterator();
+      
+      while (iter.hasNext())
+      {
+         Ack ack = (Ack)iter.next();
+         
+         Long id = new Long(ack.getDeliveryId());
+           
+         Delivery del = (Delivery)deliveries.get(id);
+         
+         if (del == null)
+         {
+            throw new IllegalStateException("Cannot find delivery to acknowledge " + ack);
+         }
+                           
+         deliveryCallback.addDeliveryId(id);
+         
+         del.acknowledge(tx);
+      }      
    }
    
-   protected ServerBrowserEndpoint removeBrowserDelegate(int browserID)
-   {
-      return (ServerBrowserEndpoint)browsers.remove(new Integer(browserID));
-   }
-
    /**
     * Starts this session's Consumers
     */
-   protected void setStarted(boolean s) throws Throwable
+   void setStarted(boolean s) throws Throwable
    {
       synchronized(consumers)
       {
@@ -747,26 +935,12 @@
             }
          }
       }
-   }   
+   } 
 
+   // Protected -----------------------------------------------------        
+
    // Private -------------------------------------------------------
-   
-   private void acknowledgeInternal(AckInfo ackInfo) throws Throwable
-   {
-      //If the message was delivered via a connection consumer then the message needs to be acked
-      //via the original consumer that was used to feed the connection consumer - which
-      //won't be one of the consumers of this session
-      //Therefore we always look in the global map of consumers held in the server peer
-      ServerConsumerEndpoint consumer = this.connectionEndpoint.getConsumerEndpoint(ackInfo.getConsumerID());
-
-      if (consumer == null)
-      {
-         throw new IllegalArgumentException("Cannot find consumer id: " + ackInfo.getConsumerID());
-      }
       
-      consumer.acknowledge(ackInfo.getMessageID());
-   }
-   
    private ConsumerDelegate failoverConsumer(JBossDestination jmsDestination,
             String selectorString,
             boolean noLocal,  String subscriptionName,
@@ -804,27 +978,27 @@
          
          new ServerConsumerEndpoint(consumerID, binding.getQueue(),
                   binding.getQueue().getName(), this, selectorString, noLocal,
-                  jmsDestination, prefetchSize, dlq);
+                  jmsDestination, prefetchSize);
       
       JMSDispatcher.instance.registerTarget(new Integer(consumerID), new ConsumerAdvised(ep));
       
       ClientConsumerDelegate stub =
          new ClientConsumerDelegate(consumerID, binding.getQueue().getChannelID(),
                   prefetchSize, maxDeliveryAttempts);
+            
+      synchronized (consumers)
+      {      
+         consumers.put(new Integer(consumerID), ep);
+      }
       
-      
-      putConsumerEndpoint(consumerID, ep); // caching consumer locally
-      
-      connectionEndpoint.getServerPeer().putConsumerEndpoint(consumerID, ep); // cachin consumer in server peer
-      
       return stub;
    }
    
    private ConsumerDelegate createConsumerDelegateInternal(JBossDestination jmsDestination,
-            String selectorString,
-            boolean noLocal,
-            String subscriptionName,
-            boolean isCC) throws Throwable
+                                                           String selectorString,
+                                                           boolean noLocal,
+                                                           String subscriptionName,
+                                                           boolean isCC) throws Throwable
    {
       if (closed)
       {
@@ -993,8 +1167,10 @@
                
                if (trace) { log.trace("selector " + (selectorChanged ? "has" : "has NOT") + " changed"); }
                
-               boolean topicChanged = !binding.getCondition().equals(jmsDestination.getName());
+               JMSCondition cond = (JMSCondition)binding.getCondition();
                
+               boolean topicChanged = !cond.getName().equals(jmsDestination.getName());
+               
                if (log.isTraceEnabled()) { log.trace("topic " + (topicChanged ? "has" : "has NOT") + " changed"); }
                
                if (selectorChanged || topicChanged)
@@ -1069,7 +1245,7 @@
       ServerConsumerEndpoint ep =
          new ServerConsumerEndpoint(consumerID, (PagingFilteredQueue)binding.getQueue(),
                   binding.getQueue().getName(), this, selectorString, noLocal,
-                  jmsDestination, prefetchSize, dlq);
+                  jmsDestination, prefetchSize);
       
       JMSDispatcher.instance.registerTarget(new Integer(consumerID), new ConsumerAdvised(ep));
       
@@ -1077,14 +1253,82 @@
          new ClientConsumerDelegate(consumerID, binding.getQueue().getChannelID(),
                   prefetchSize, maxDeliveryAttempts);
       
-      putConsumerEndpoint(consumerID, ep); // caching consumer locally
-      
-      connectionEndpoint.getServerPeer().putConsumerEndpoint(consumerID, ep); // cachin consumer in server peer
-      
+      synchronized (consumers)
+      {
+         consumers.put(new Integer(consumerID), ep);
+      }
+         
       log.debug("created and registered " + ep);
       
       return stub;
    }
-
+   
+   private void promptDelivery(Set channels)
+   {
+      //Now prompt delivery on the channels
+      Iterator iter = channels.iterator();
+      
+      while (iter.hasNext())
+      {
+         DeliveryObserver observer = (DeliveryObserver)iter.next();
+         
+         ((Channel)observer).deliver(false);
+      }
+   }
+   
+   
    // Inner classes -------------------------------------------------
+   
+   /**
+    * 
+    * The purpose of this class is to remove deliveries from the delivery list on commit
+    * Each transaction has once instance of this per SCE
+    *
+    */
+   private class DeliveryCallback implements TxCallback
+   {
+      List delList = new ArrayList();
+         
+      public void beforePrepare()
+      {         
+         //NOOP
+      }
+      
+      public void beforeCommit(boolean onePhase)
+      {         
+         //NOOP
+      }
+      
+      public void beforeRollback(boolean onePhase)
+      {         
+         //NOOP
+      }
+      
+      public void afterPrepare()
+      {         
+         //NOOP
+      }
+      
+      public synchronized void afterCommit(boolean onePhase) throws TransactionException
+      {
+         // Remove the deliveries from the delivery map.
+         Iterator iter = delList.iterator();
+         while (iter.hasNext())
+         {
+            Long deliveryId = (Long)iter.next();
+            
+            deliveries.remove(deliveryId);
+         }
+      }
+      
+      public void afterRollback(boolean onePhase) throws TransactionException
+      {                            
+         //NOOP
+      }
+      
+      synchronized void addDeliveryId(Long deliveryId)
+      {
+         delList.add(deliveryId);
+      }
+   }
 }

Modified: trunk/src/main/org/jboss/jms/server/endpoint/SessionEndpoint.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/SessionEndpoint.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/SessionEndpoint.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -33,7 +33,6 @@
 import org.jboss.jms.destination.JBossQueue;
 import org.jboss.jms.destination.JBossTopic;
 import org.jboss.jms.message.JBossMessage;
-import org.jboss.jms.tx.AckInfo;
 
 /**
  * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
@@ -73,14 +72,14 @@
     * @param ackInfos
     * @throws JMSException
     */
-   void acknowledgeBatch(List ackInfos) throws JMSException;
+   void acknowledgeBatch(List deliveryIds) throws JMSException;
    
    /**
     * Acknowledge a message - used for auto acknowledge
-    * @param ackInfo
+    * @param deliveryId
     * @throws JMSException
     */
-   void acknowledge(AckInfo ackInfo) throws JMSException;
+   void acknowledge(Ack ack) throws JMSException;
    
    /**
     * Add a temporary destination.
@@ -114,15 +113,14 @@
     * or at session recovery to cancel any messages that couldn't be redelivered locally
     * @param ackInfos
     */
-   void cancelDeliveries(List ackInfos) throws JMSException;
-   
-   
+   void cancelDeliveries(List cancelInfos) throws JMSException;
+      
    /**
-    * Send a list of unacked ackInfos to the server so the delivery lists can be repopulated
+    * Send delivery info to the server so the delivery lists can be repopulated
     * used at failover
     * @param ackInfos
     * @throws JMSException
     */
-   void sendUnackedAckInfos(List ackInfos) throws JMSException;
+   void recoverDeliveries(List createInfos) throws JMSException;
 }
 

Modified: trunk/src/main/org/jboss/jms/server/endpoint/advised/BrowserAdvised.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/advised/BrowserAdvised.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/advised/BrowserAdvised.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -65,11 +65,6 @@
       endpoint.closing();
    }
 
-   public boolean isClosed()
-   {
-      return endpoint.isClosed();
-   }
-
    public boolean hasNextMessage() throws JMSException
    {
       return endpoint.hasNextMessage();
@@ -84,6 +79,11 @@
    {
       return endpoint.nextMessageBlock(maxMessages);
    }
+   
+   public boolean isClosed() throws JMSException
+   {
+      return endpoint.isClosed();
+   }
 
    // AdvisedSupport overrides --------------------------------------
    

Modified: trunk/src/main/org/jboss/jms/server/endpoint/advised/ConnectionAdvised.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/advised/ConnectionAdvised.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/advised/ConnectionAdvised.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -67,11 +67,6 @@
       endpoint.closing();
    }
 
-   public boolean isClosed()
-   {
-      return endpoint.isClosed();
-   }
-
    public SessionDelegate createSessionDelegate(boolean transacted,
                                                 int acknowledgmentMode,
                                                 boolean isXA) throws JMSException
@@ -108,6 +103,11 @@
    {
       return endpoint.getPreparedTransactions();
    }
+   
+   public boolean isClosed() throws JMSException
+   {
+      return endpoint.isClosed();
+   }
 
    // Public --------------------------------------------------------
 

Modified: trunk/src/main/org/jboss/jms/server/endpoint/advised/ConsumerAdvised.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/advised/ConsumerAdvised.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/advised/ConsumerAdvised.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -64,11 +64,6 @@
       endpoint.closing();
    }
 
-   public boolean isClosed()
-   {
-      return endpoint.isClosed();
-   }
-
    public void more() throws JMSException
    {
       endpoint.more();
@@ -78,6 +73,11 @@
    {
       endpoint.confirmDelivery(count);
    }
+   
+   public boolean isClosed() throws JMSException
+   {
+      return endpoint.isClosed();
+   }
 
   
    // AdvisedSupport overrides --------------------------------------

Modified: trunk/src/main/org/jboss/jms/server/endpoint/advised/SessionAdvised.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/endpoint/advised/SessionAdvised.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/endpoint/advised/SessionAdvised.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -31,8 +31,8 @@
 import org.jboss.jms.destination.JBossQueue;
 import org.jboss.jms.destination.JBossTopic;
 import org.jboss.jms.message.JBossMessage;
+import org.jboss.jms.server.endpoint.Ack;
 import org.jboss.jms.server.endpoint.SessionEndpoint;
-import org.jboss.jms.tx.AckInfo;
 
 /**
  * The server-side advised instance corresponding to a Session. It is bound to the AOP
@@ -74,11 +74,6 @@
       endpoint.closing();
    }
 
-   public boolean isClosed()
-   {
-      return endpoint.isClosed();
-   }
-
    public void send(JBossMessage msg) throws JMSException
    {
       endpoint.send(msg);
@@ -107,12 +102,12 @@
       return endpoint.createTopic(topicName);
    }
 
-   public void acknowledgeBatch(List ackInfos) throws JMSException
+   public void acknowledgeBatch(List acks) throws JMSException
    {
-      endpoint.acknowledgeBatch(ackInfos);
+      endpoint.acknowledgeBatch(acks);
    }
    
-   public void acknowledge(AckInfo ack) throws JMSException
+   public void acknowledge(Ack ack) throws JMSException
    {
       endpoint.acknowledge(ack);
    }
@@ -137,11 +132,16 @@
       endpoint.cancelDeliveries(ackInfos);
    }
    
-   public void sendUnackedAckInfos(List ackInfos) throws JMSException
+   public void recoverDeliveries(List ackInfos) throws JMSException
    {
-      endpoint.sendUnackedAckInfos(ackInfos);
+      endpoint.recoverDeliveries(ackInfos);
    }
 
+   public boolean isClosed() throws JMSException
+   {
+      return endpoint.isClosed();
+   }
+   
 
    // AdvisedSupport overrides --------------------------------------
 

Modified: trunk/src/main/org/jboss/jms/server/remoting/JMSWireFormat.java
===================================================================
--- trunk/src/main/org/jboss/jms/server/remoting/JMSWireFormat.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/server/remoting/JMSWireFormat.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -42,8 +42,11 @@
 import org.jboss.jms.message.JBossMessage;
 import org.jboss.jms.server.ServerPeer;
 import org.jboss.jms.server.Version;
+import org.jboss.jms.server.endpoint.Ack;
+import org.jboss.jms.server.endpoint.Cancel;
 import org.jboss.jms.server.endpoint.ClientDelivery;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.server.endpoint.DefaultAck;
+import org.jboss.jms.server.endpoint.DeliveryRecovery;
 import org.jboss.jms.tx.TransactionRequest;
 import org.jboss.logging.Logger;
 import org.jboss.messaging.core.message.MessageFactory;
@@ -95,7 +98,8 @@
    protected static final byte MORE = 5;
    protected static final byte SEND_TRANSACTION = 6;
    protected static final byte GET_ID_BLOCK = 7;
-   protected static final byte UNACKED_ACKINFOS = 8;
+   protected static final byte RECOVER_DELIVERIES = 8;
+   protected static final byte CONFIRM_DELIVERY = 9;
  
 
    // The response codes - start from 100
@@ -233,9 +237,9 @@
    
                   writeHeader(mi, dos);
                   
-                  AckInfo ack = (AckInfo)mi.getArguments()[0];
+                  Ack ack = (Ack)mi.getArguments()[0];
                   
-                  ack.write(dos);
+                  dos.writeLong(ack.getDeliveryId());
    
                   dos.flush();
    
@@ -255,8 +259,8 @@
    
                   while (iter.hasNext())
                   {
-                     AckInfo ack = (AckInfo)iter.next();
-                     ack.write(dos);
+                     Ack ack = (Ack)iter.next();
+                     dos.writeLong(ack.getDeliveryId());
                   }
    
                   dos.flush();
@@ -305,17 +309,17 @@
    
                   while (iter.hasNext())
                   {
-                     AckInfo ack = (AckInfo)iter.next();
-                     ack.write(dos);
+                     Cancel cancel = (Cancel)iter.next();
+                     cancel.write(dos);
                   }
    
                   dos.flush();
    
                   if (trace) { log.trace("wrote cancelDeliveries()"); }
                }
-               else if ("sendUnackedAckInfos".equals(methodName) && mi.getArguments() != null)
+               else if ("recoverDeliveries".equals(methodName) && mi.getArguments() != null)
                {
-                  dos.writeByte(UNACKED_ACKINFOS);
+                  dos.writeByte(RECOVER_DELIVERIES);
    
                   writeHeader(mi, dos);
    
@@ -327,14 +331,28 @@
    
                   while (iter.hasNext())
                   {
-                     AckInfo ack = (AckInfo)iter.next();
-                     ack.write(dos);
+                     DeliveryRecovery d = (DeliveryRecovery)iter.next();
+                     d.write(dos);
                   }
    
                   dos.flush();
    
                   if (trace) { log.trace("wrote sendUnackedAckInfos()"); }
                }
+               else if ("confirmDelivery".equals(methodName))
+               {
+                  dos.writeByte(CONFIRM_DELIVERY);
+   
+                  writeHeader(mi, dos);
+   
+                  Integer count = (Integer)mi.getArguments()[0];
+   
+                  dos.writeInt(count.intValue());
+                     
+                  dos.flush();
+   
+                  if (trace) { log.trace("wrote confirmDelivery()"); }
+               }
                else
                {
                   dos.write(SERIALIZED);
@@ -483,14 +501,6 @@
 
                   // We don't use acknowledgeable push callbacks
 
-//                  Map payload = callback.getReturnPayload();
-//                  String guid = (String)payload.get(ServerInvokerCallbackHandler.CALLBACK_ID);
-//                  dos.writeUTF(guid);
-//                  String listenerId = (String)payload.get(Client.LISTENER_ID_KEY);
-//                  dos.writeUTF(listenerId);
-//                  String acks = (String)payload.get(ServerInvokerCallbackHandler.REMOTING_ACKNOWLEDGES_PUSH_CALLBACKS);
-//                  dos.writeUTF(acks);
-                  
                   MessagingMarshallable mm = (MessagingMarshallable)callback.getParameter();
                   ClientDelivery delivery = (ClientDelivery)mm.getLoad();
                   delivery.write(dos);
@@ -649,11 +659,9 @@
             {
                MethodInvocation mi = readHeader(dis);
                
-               AckInfo info = new AckInfo();
+               long l = dis.readLong();
                
-               info.read(dis);
-               
-               Object[] args = new Object[] {info};
+               Object[] args = new Object[] {new DefaultAck(l)};
    
                mi.setArguments(args);
    
@@ -675,11 +683,9 @@
                
                for (int i = 0; i < num; i++)
                {
-                  AckInfo ack = new AckInfo();
+                  long l = dis.readLong();                  
                   
-                  ack.read(dis);
-                  
-                  acks.add(ack);
+                  acks.add(new DefaultAck(l));
                }
                            
                Object[] args = new Object[] {acks};
@@ -704,11 +710,11 @@
    
                for (int i = 0; i < size; i++)
                {
-                  AckInfo ack = new AckInfo();
+                  Cancel cancel = new Cancel();
                   
-                  ack.read(dis);
+                  cancel.read(dis);
                   
-                  acks.add(ack);
+                  acks.add(cancel);
                }
    
                Object[] args = new Object[] {acks};
@@ -723,24 +729,24 @@
    
                return request;
             }
-            case UNACKED_ACKINFOS:
+            case RECOVER_DELIVERIES:
             {
                MethodInvocation mi = readHeader(dis);
    
                int size = dis.readInt();
    
-               List acks = new ArrayList(size);
+               List dels = new ArrayList(size);
    
                for (int i = 0; i < size; i++)
                {
-                  AckInfo ack = new AckInfo();
+                  DeliveryRecovery d = new DeliveryRecovery();
                   
-                  ack.read(dis);
+                  d.read(dis);
                   
-                  acks.add(ack);
+                  dels.add(d);
                }
    
-               Object[] args = new Object[] {acks};
+               Object[] args = new Object[] {dels};
    
                mi.setArguments(args);
    
@@ -752,6 +758,24 @@
    
                return request;
             }
+            case CONFIRM_DELIVERY:
+            {
+               MethodInvocation mi = readHeader(dis);
+   
+               int count = dis.readInt();                  
+   
+               Object[] args = new Object[] {new Integer(count)};
+   
+               mi.setArguments(args);
+   
+               InvocationRequest request =
+                  new InvocationRequest(null, ServerPeer.REMOTING_JMS_SUBSYSTEM,
+                                        new MessagingMarshallable(version, mi), null, null, null);
+   
+               if (trace) { log.trace("read confirmDelivery()"); }
+   
+               return request;
+            }
             case ID_BLOCK_RESPONSE:
             {
                IdBlock block = new IdBlock();
@@ -852,18 +876,11 @@
                {
                   // We don't use acknowledgeable push callbacks
 
-//                  String guid = dis.readUTF();
-//                  String listenerId = dis.readUTF();
-//                  String acks = dis.readUTF();
                   ClientDelivery delivery = new ClientDelivery();
                   delivery.read(dis);
                   MessagingMarshallable mm = new MessagingMarshallable(version, delivery);
                   Callback callback = new Callback(mm);
-//                  HashMap payload = new HashMap();
-//                  payload.put(ServerInvokerCallbackHandler.CALLBACK_ID, guid);
-//                  payload.put(Client.LISTENER_ID_KEY, listenerId);
-//                  payload.put(ServerInvokerCallbackHandler.REMOTING_ACKNOWLEDGES_PUSH_CALLBACKS, acks);
-//                  callback.setReturnPayload(payload);
+
                   callbackList.add(callback);
                }
 

Deleted: trunk/src/main/org/jboss/jms/tx/AckInfo.java
===================================================================
--- trunk/src/main/org/jboss/jms/tx/AckInfo.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/tx/AckInfo.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -1,147 +0,0 @@
-/*
-  * 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.jms.tx;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-
-import org.jboss.jms.message.MessageProxy;
-import org.jboss.messaging.util.Streamable;
-
-/**
- * Struct like class for holding information regarding an acknowledgement to be passed to the server
- * for processing.
- * 
- * @author <a href="mailto:tim.fox at jboss.com>Tim Fox </a>
- * @author <a href="mailto:ovidiu at jboss.com>Ovidiu Feodorov</a>
- *
- * $Id$
- */
-public class AckInfo implements Streamable
-{
-   // Constants -----------------------------------------------------
-   
-   // Attributes ----------------------------------------------------
-   
-   protected long messageID;
-   protected int consumerID;
-   protected int deliveryCount;
-
-   protected MessageProxy msg;
-   
-   // Static --------------------------------------------------------
-   
-   // Constructors --------------------------------------------------
-   
-   public AckInfo()
-   {      
-   }
-
-   public AckInfo(MessageProxy proxy, int consumerID)
-   {
-      this.msg = proxy;
-      this.messageID = proxy.getMessage().getMessageID();
-      this.consumerID = consumerID;
-   }
-   
-   //Only used for testing
-   public AckInfo(long messageID, int consumerID, int deliveryCount)
-   {
-      this.messageID = messageID;
-      this.consumerID = consumerID;
-      this.deliveryCount = deliveryCount;
-   }
-
-   // Public --------------------------------------------------------
-   
-   public long getMessageID()
-   {
-      return messageID;
-   }
-   
-   public int getConsumerID()
-   {
-      return consumerID;
-   }
-
-   /** Used to change ack's id during failover */
-   public void setConsumerID(int consumerID)
-   {
-       this.consumerID = consumerID;
-   }
-   
-   public MessageProxy getMessage()
-   {
-      return msg;
-   }
-   
-   public int getDeliveryCount()
-   {
-      if (msg == null)
-      {
-         return deliveryCount;
-      }
-      else
-      {
-         return msg.getDeliveryCount();
-      }
-   }
-
-   public String toString()
-   {
-      return "AckInfo[" + messageID + ", " + consumerID + "]";
-   }
-
-   // Streamable implementation ---------------------------------
-
-   public void write(DataOutputStream out) throws Exception
-   {
-     out.writeLong(messageID);
-     out.writeInt(consumerID);
-     if (msg != null)
-     {
-        out.writeInt(msg.getDeliveryCount());
-     }
-     else
-     {
-        out.writeInt(deliveryCount);
-     }
-   }
-
-   public void read(DataInputStream in) throws Exception
-   {
-      messageID = in.readLong();
-      consumerID = in.readInt();
-      deliveryCount = in.readInt();
-   }
-   
-   // Class YYY overrides -------------------------------------------
-
-   // Protected -----------------------------------------------------
-
-   // Package Private -----------------------------------------------
-
-   // Private -------------------------------------------------------
-   
-   // Inner Classes -------------------------------------------------
-   
-}

Copied: trunk/src/main/org/jboss/jms/tx/ClientTransaction.java (from rev 1783, trunk/src/main/org/jboss/jms/tx/TxState.java)
===================================================================
--- trunk/src/main/org/jboss/jms/tx/TxState.java	2006-12-13 09:46:39 UTC (rev 1783)
+++ trunk/src/main/org/jboss/jms/tx/ClientTransaction.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -0,0 +1,391 @@
+/*
+ * 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.jms.tx;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.jboss.jms.client.state.SessionState;
+import org.jboss.jms.message.JBossMessage;
+import org.jboss.jms.server.endpoint.Ack;
+import org.jboss.jms.server.endpoint.DefaultAck;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
+import org.jboss.messaging.core.message.MessageFactory;
+
+/**
+ * Holds the state of a transaction on the client side
+ * 
+ * @author <a href="mailto:tim.fox at jboss.com>Tim Fox </a>
+ */
+public class ClientTransaction
+{  
+   // Constants -----------------------------------------------------
+
+   public final static byte TX_OPEN = 0;
+   
+   public final static byte TX_ENDED = 1;
+   
+   public final static byte TX_PREPARED = 2;
+   
+   public final static byte TX_COMMITED = 3;
+   
+   public final static byte TX_ROLLEDBACK = 4;
+   
+   // Attributes ----------------------------------------------------
+   
+   private int state = TX_OPEN;
+   
+   //Maintained on the client side
+   private Map sessionStatesMap;
+   
+   //Read from on the server side
+   private List sessionStatesList;
+   
+   private boolean clientSide;
+   
+   // Static --------------------------------------------------------
+   
+   // Constructors --------------------------------------------------
+   
+   public ClientTransaction()
+   {                  
+      clientSide = true;
+   }
+   
+   // Public --------------------------------------------------------
+   
+   public int getState()
+   {
+      return state;
+   }
+   
+   public void addMessage(int sessionId, JBossMessage msg)
+   {
+      if (!clientSide)
+      {
+         throw new IllegalStateException("Cannot call this method on the server side");
+      }
+      SessionTxState sessionTxState = getSessionTxState(sessionId);
+      
+      sessionTxState.addMessage(msg);
+   }
+   
+   public void addAck(int sessionId, DeliveryInfo info)
+   {
+      if (!clientSide)
+      {
+         throw new IllegalStateException("Cannot call this method on the server side");
+      }
+      SessionTxState sessionTxState = getSessionTxState(sessionId);
+      
+      sessionTxState.addAck(info);
+   }      
+   
+   public void clearMessages()
+   {
+      if (!clientSide)
+      {
+         throw new IllegalStateException("Cannot call this method on the server side");
+      }
+      Iterator iter = sessionStatesMap.values().iterator();
+      
+      while (iter.hasNext())
+      {
+         SessionTxState sessionTxState = (SessionTxState)iter.next();
+         
+         sessionTxState.clearMessages();
+      }
+   }
+   
+   public void setState(int state)
+   {
+      if (!clientSide)
+      {
+         throw new IllegalStateException("Cannot call this method on the server side");
+      }
+      this.state = state;
+   }
+   
+   public Collection getSessionStates()
+   {
+      if (sessionStatesList != null)
+      {
+         return sessionStatesList;
+      }
+      else
+      {
+         return sessionStatesMap.values();
+      }
+   }   
+   
+   /*
+    * Substitute newSessionId for oldSessionId
+    */
+   public void handleFailover(Map oldNewSessionMap)
+   {    
+      if (!clientSide)
+      {
+         throw new IllegalStateException("Cannot call this method on the server side");
+      }
+      //Note we have to do this in one go since there may be overlap between old and new session ids
+      //and we don't want to overwrite keys in the map
+      
+      if (sessionStatesMap != null)
+      {         
+         Map newMap = new HashMap();
+         
+         Iterator iter = oldNewSessionMap.entrySet().iterator();
+         
+         while (iter.hasNext())
+         {
+            Map.Entry entry = (Map.Entry)iter.next();
+            
+            Integer oldSessionId = (Integer)entry.getKey();
+            
+            SessionState newSessionState = (SessionState)entry.getValue();
+            
+            int newSessionId = newSessionState.getSessionId();
+            
+            SessionTxState state = (SessionTxState)sessionStatesMap.get(oldSessionId);
+            
+            if (state != null)
+            {
+               state.handleFailover(newSessionId);
+            }
+            
+            newMap.put(new Integer(newSessionId), state);
+            
+         }
+       
+         sessionStatesMap = newMap;
+      }
+   }
+   
+   public List getDeliveriesForSession(int sessionId)
+   {
+      if (!clientSide)
+      {
+         throw new IllegalStateException("Cannot call this method on the server side");
+      }
+      SessionTxState state = getSessionTxState(sessionId);
+      
+      if (state != null)
+      {
+         return state.getAcks();
+      }
+      else
+      {
+         return null;
+      }
+   }
+   
+   // Streamable implementation ---------------------------------
+   
+   public void write(DataOutputStream out) throws Exception
+   {
+      out.writeInt(state);
+      
+      out.writeInt(sessionStatesMap.size());
+      
+      Iterator iter = sessionStatesMap.values().iterator();
+      
+      while (iter.hasNext())
+      {
+         SessionTxState state = (SessionTxState)iter.next();
+         
+         out.writeInt(state.getSessionId());
+         
+         List msgs = state.getMsgs();
+         
+         out.writeInt(msgs.size());
+         
+         Iterator iter2 = msgs.iterator();
+         
+         while (iter2.hasNext())
+         {
+            JBossMessage m = (JBossMessage)iter2.next();
+
+            out.writeByte(m.getType());
+            
+            m.write(out);
+         }
+         
+         List acks = state.getAcks();
+         
+         out.writeInt(acks.size());
+         
+         iter2 = acks.iterator();
+         
+         while (iter2.hasNext())
+         {
+            DeliveryInfo ack = (DeliveryInfo)iter2.next();
+
+            //We only need the delivery id written
+            out.writeLong(ack.getMessageProxy().getDeliveryId());
+         }
+      }
+   }  
+    
+   
+   public void read(DataInputStream in) throws Exception
+   {
+      clientSide = false;
+      
+      state = in.readInt();
+      
+      int numSessions = in.readInt();
+      
+      //Read in as a list since we don't want the extra overhead of putting into a map
+      //which won't be used on the server side
+      sessionStatesList = new ArrayList(numSessions);
+      
+      for (int i = 0; i < numSessions; i++)
+      {
+         int sessionId = in.readInt();
+         
+         SessionTxState sessionState = new SessionTxState(sessionId);
+         
+         sessionStatesList.add(sessionState);
+         
+         int numMsgs = in.readInt();
+         
+         for (int j = 0; j < numMsgs; j++)            
+         {
+            byte type = in.readByte();
+            
+            JBossMessage msg = (JBossMessage)MessageFactory.createMessage(type);
+            
+            msg.read(in);
+            
+            sessionState.addMessage(msg);
+         }
+         
+         int numAcks = in.readInt();
+         
+         for (int j = 0; j < numAcks; j++)            
+         {
+            long ack = in.readLong();
+            
+            sessionState.addAck(new DefaultAck(ack));
+         }
+      }      
+   }
+   
+   // Protected -----------------------------------------------------
+   
+   // Package Private -----------------------------------------------
+   
+   // Private -------------------------------------------------------
+   
+   private SessionTxState getSessionTxState(int sessionId)
+   {                  
+      if (sessionStatesMap == null)
+      {
+         sessionStatesMap = new HashMap();
+      }
+      
+      SessionTxState sessionTxState = (SessionTxState)sessionStatesMap.get(new Integer(sessionId));
+      
+      if (sessionTxState == null)
+      {
+         sessionTxState = new SessionTxState(sessionId);
+         
+         sessionStatesMap.put(new Integer(sessionId), sessionTxState);
+      }
+      
+      return sessionTxState;
+   }
+   
+   
+      
+   // Inner Classes -------------------------------------------------
+   
+   public class SessionTxState
+   {
+      SessionTxState(int sessionId)
+      {
+         this.sessionId = sessionId;
+      }
+      
+      void addMessage(JBossMessage msg)
+      {
+         msgs.add(msg);
+      }
+      
+      void addAck(Ack ack)
+      {
+         acks.add(ack);
+      }
+      
+      public List getMsgs()
+      {
+         return msgs;
+      }
+      
+      public List getAcks()
+      {
+         return acks;
+      }
+      
+      public int getSessionId()
+      {
+         return sessionId;
+      }
+      
+      void handleFailover(int newSessionId)
+      {
+         this.sessionId = newSessionId;
+         
+         //Remove any non persistent acks
+         
+         Iterator iter = acks.iterator();
+         
+         while (iter.hasNext())
+         {
+            DeliveryInfo info = (DeliveryInfo)iter.next();
+            
+            if (!info.getMessageProxy().getMessage().isReliable())
+            {
+               iter.remove();
+            }
+         }
+      }
+      
+      void clearMessages()
+      {
+         msgs.clear();
+      }
+      
+      private int sessionId;
+      
+      private List msgs = new ArrayList();
+      
+      private List acks = new ArrayList();            
+   }
+      
+}

Modified: trunk/src/main/org/jboss/jms/tx/ResourceManager.java
===================================================================
--- trunk/src/main/org/jboss/jms/tx/ResourceManager.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/tx/ResourceManager.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -22,16 +22,13 @@
 package org.jboss.jms.tx;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import javax.jms.IllegalStateException;
 import javax.jms.JMSException;
-import javax.jms.Message;
 import javax.jms.TransactionRolledBackException;
 import javax.transaction.xa.XAException;
 import javax.transaction.xa.XAResource;
@@ -39,6 +36,10 @@
 
 import org.jboss.jms.delegate.ConnectionDelegate;
 import org.jboss.jms.delegate.SessionDelegate;
+import org.jboss.jms.message.JBossMessage;
+import org.jboss.jms.message.MessageProxy;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
+import org.jboss.jms.tx.ClientTransaction.SessionTxState;
 import org.jboss.jms.util.MessagingTransactionRolledBackException;
 import org.jboss.jms.util.MessagingXAException;
 import org.jboss.logging.Logger;
@@ -66,7 +67,7 @@
    
    private boolean trace = log.isTraceEnabled();
    
-   protected ConcurrentHashMap transactions = new ConcurrentHashMap();
+   private ConcurrentHashMap transactions = new ConcurrentHashMap();
    
    // Static --------------------------------------------------------
    
@@ -76,24 +77,20 @@
     
    // Public --------------------------------------------------------
    
-   public TxState getTx(Object xid)
+   /**
+    * Remove a tx
+    */
+   public ClientTransaction removeTx(Object xid)
    {
-      if (trace) { log.trace("getting transaction for " + xid); }
-      
-      return (TxState)transactions.get(xid);
+      return removeTxInternal(xid);
    }
-   
-   public TxState removeTx(Object xid)
-   {
-      return (TxState)transactions.remove(xid);
-   }
-   
+            
    /**
     * Create a local tx.
     */
    public LocalTx createLocalTx()
    {
-      TxState tx = new TxState();
+      ClientTransaction tx = new ClientTransaction();
       
       LocalTx xid = getNextTxId();
       
@@ -108,70 +105,58 @@
     * @param xid - The id of the transaction to add the message to
     * @param m The message
     */
-   public void addMessage(Object xid, Message m)
+   public void addMessage(Object xid, int sessionId, JBossMessage msg)
    {
       if (trace) { log.trace("addding message for xid " + xid); }
       
-      TxState tx = getTx(xid);
+      ClientTransaction tx = getTxInternal(xid);
       
-      tx.getMessages().add(m);
+      tx.addMessage(sessionId, msg);
    }
-
-    /**
-     * Navigate on ACK and change consumer ids on every ACK not sent yet.
-     */
-    public void handleFailover(int oldConsumerID, int newConsumerID)
-    {
-        if (trace) { log.trace("handleFailover:: Transfering consumer id on ACKs from  " + oldConsumerID + " to " + newConsumerID); }
-
-        //TODO need to lock the rm while this is happening
-        
-        //Note we need to replace ids for *all* transactions - this is because, for XA
-        //the session might have done work in many transactions
-        Iterator iter = this.transactions.values().iterator();
-        
-        while (iter.hasNext())
-        {
-           TxState tx = (TxState)iter.next();
-           
-           tx.handleFailover(oldConsumerID, newConsumerID);
-        }                
-    }
-    
-    /*
-     * Get all the ackinfos with a consumer id in the specified set
-     */
-    public List getAckInfosForConsumerIds(Set consumerIds)
-    {
-       Iterator iter = this.transactions.values().iterator();
-       
-       List ackInfos = new ArrayList();
-       
-       while (iter.hasNext())
-       {
-          TxState tx = (TxState)iter.next();
-          
-          tx.getAckInfosForConsumerIds(ackInfos, consumerIds);
-       }
-       
-       return ackInfos;
-    }
-    
-    public void removeNonPersistentAcks(Set consumerIds)
-    {
-       Iterator iter = this.transactions.values().iterator();
-       
-       List ackInfos = new ArrayList();
-       
-       while (iter.hasNext())
-       {
-          TxState tx = (TxState)iter.next();
-          
-          tx.removeNonPersistentAcks(consumerIds);
-       }
-    }
-
    
+   /*
+    * Failover session from old session -> new session
+    * This basically involves updating the session id
+    */
+   public void handleFailover(Map oldNewSessionMap)
+   {
+      //Note we need to replace ids for *all* transactions - this is because, for XA
+      //the session might have done work in many transactions
+      Iterator iter = this.transactions.values().iterator();
+      
+      while (iter.hasNext())
+      {
+         ClientTransaction tx = (ClientTransaction)iter.next();
+         
+         tx.handleFailover(oldNewSessionMap);
+      }                
+   }   
+   
+   /*
+    * Get all the deliveries corresponding to the session id
+    */
+   public List getDeliveriesForSession(int sessionId)
+   {
+      Iterator iter = this.transactions.values().iterator();
+      
+      List ackInfos = new ArrayList();
+      
+      while (iter.hasNext())
+      {
+         ClientTransaction tx = (ClientTransaction)iter.next();
+         
+         List acks = tx.getDeliveriesForSession(sessionId);
+         
+         if (acks != null)
+         {
+            ackInfos.addAll(acks);
+         }
+      }
+      
+      return ackInfos;
+   }
+   
+   
    /**
     * Add an acknowledgement to the transaction
     * 
@@ -180,25 +165,25 @@
     * @param sessionState - the session the ack is in - we need this so on rollback we can tell each session
     * to redeliver it's messages
     */
-   public void addAck(Object xid, AckInfo ackInfo) throws JMSException
+   public void addAck(Object xid, int sessionId, DeliveryInfo ackInfo) throws JMSException
    {
       if (trace) { log.trace("adding " + ackInfo + " to transaction " + xid); }
       
-      TxState tx = getTx(xid);
+      ClientTransaction tx = getTxInternal(xid);
       
       if (tx == null)
       {
          throw new JMSException("There is no transaction with id " + xid);
       }
       
-      tx.getAcks().add(ackInfo);
+      tx.addAck(sessionId, ackInfo);
    }
          
    public void commitLocal(LocalTx xid, ConnectionDelegate connection) throws JMSException
    {
       if (trace) { log.trace("commiting local xid " + xid); }
       
-      TxState tx = this.getTx(xid);
+      ClientTransaction tx = this.getTxInternal(xid);
       
       //Invalid xid
       if (tx == null)
@@ -215,7 +200,7 @@
          
          //If we get this far we can remove the transaction
          
-         this.removeTx(xid);
+         this.removeTxInternal(xid);
       }
       catch (Throwable t)
       {
@@ -233,7 +218,7 @@
    {
       if (trace) { log.trace("rolling back local xid " + xid); }
       
-      TxState ts = removeTx(xid);
+      ClientTransaction ts = removeTxInternal(xid);
       
       if (ts == null)
       {      
@@ -241,6 +226,7 @@
       }
       
       // don't need messages for rollback
+      // We don't clear the acks since we need to redeliver locally
       ts.clearMessages();
       
       // for one phase rollback there is nothing to do on the server
@@ -248,11 +234,27 @@
       redeliverMessages(ts);
    }
    
-   public void commit(Xid xid, boolean onePhase, ConnectionDelegate connection) throws XAException
+   //Only used for testing
+   public ClientTransaction getTx(Object xid)
    {
+      return getTxInternal(xid);
+   }
+   
+   //Only used for testing
+   public int size()
+   {
+      return transactions.size();
+   }
+    
+   // Protected ------------------------------------------------------      
+   
+   // Package Private ------------------------------------------------
+   
+   void commit(Xid xid, boolean onePhase, ConnectionDelegate connection) throws XAException
+   {
       if (trace) { log.trace("commiting xid " + xid + ", onePhase=" + onePhase); }
       
-      TxState tx = removeTx(xid);
+      ClientTransaction tx = removeTxInternal(xid);
           
       if (onePhase)
       {
@@ -273,7 +275,7 @@
       {
          if (tx != null)
          {
-            if (tx.getState() != TxState.TX_PREPARED)
+            if (tx.getState() != ClientTransaction.TX_PREPARED)
             {    
                throw new MessagingXAException(XAException.XAER_PROTO, "commit called for transaction, but it is not prepared");
             }
@@ -295,25 +297,26 @@
       
       if (tx != null)
       {
-         tx.setState(TxState.TX_COMMITED);
+         tx.setState(ClientTransaction.TX_COMMITED);
       }
    }
       
-   public void rollback(Xid xid, ConnectionDelegate connection) throws XAException
+   void rollback(Xid xid, ConnectionDelegate connection) throws XAException
    {
       if (trace) { log.trace("rolling back xid " + xid); }
       
-      TxState tx = removeTx(xid);
+      ClientTransaction tx = removeTxInternal(xid);
           
       TransactionRequest request = null;
       
       // we don't need to send the messages to the server on a rollback
       if (tx != null)
       {
+         //We don't clear the acks since we need to redeliver locally
          tx.clearMessages();
       }
       
-      if ((tx == null) || tx.getState() == TxState.TX_PREPARED)
+      if ((tx == null) || tx.getState() == ClientTransaction.TX_PREPARED)
       {
          request = new TransactionRequest(TransactionRequest.TWO_PHASE_ROLLBACK_REQUEST, xid, tx);
          
@@ -339,78 +342,25 @@
       }
    }
    
-   
-   /*
-    * Rollback has occurred so we need to redeliver any unacked messages corresponding to the acks
-    * is in the transaction.
-    */
-   private void redeliverMessages(TxState ts) throws JMSException
+   void endTx(Xid xid, boolean success) throws XAException
    {
-      // Sort messages into lists, one for each session. We use a LinkedHashMap since we need to
-      // preserve the order of the sessions.
-
-      Map toAck = new LinkedHashMap();
-
-      for(Iterator i = ts.getAcks().iterator(); i.hasNext(); )
-      {
-         AckInfo ack = (AckInfo)i.next();
-         SessionDelegate del = ack.msg.getSessionDelegate();
-         
-         List acks = (List)toAck.get(del);
-         if (acks == null)
-         {
-            acks = new ArrayList();
-            toAck.put(del, acks);
-         }
-         acks.add(ack);
-      }
-      
-      // Now tell each session to redeliver.
-      
-      LinkedList l = new LinkedList();
-      
-      for(Iterator i = toAck.entrySet().iterator(); i.hasNext();)
-      {
-         // need to reverse the order
-         Object entry = i.next();
-         l.addFirst(entry);
-      }
-      
-      for(Iterator i = l.iterator(); i.hasNext();)
-      {
-         Map.Entry entry = (Map.Entry)i.next();
-         SessionDelegate sess = (SessionDelegate)entry.getKey();
-         List acks = (List)entry.getValue();
-         sess.redeliver(acks);
-      }  
-   }
-   
-   public int size()
-   {
-      return transactions.size();
-   }
-
-   // Protected ------------------------------------------------------
-   
-   protected void endTx(Xid xid, boolean success) throws XAException
-   {
       if (trace) { log.trace("ending " + xid + ", success=" + success); }
       
-      TxState state = getTx(xid);
+      ClientTransaction state = getTxInternal(xid);
       
       if (state == null)
       {  
          throw new MessagingXAException(XAException.XAER_NOTA, "Cannot find transaction with xid:" + xid);
       }        
       
-      state.setState(TxState.TX_ENDED);
+      state.setState(ClientTransaction.TX_ENDED);
    }
    
-   protected Xid joinTx(Xid xid) throws XAException
+   Xid joinTx(Xid xid) throws XAException
    {
       if (trace) { log.trace("joining  " + xid); }
       
-      TxState state = getTx(xid);
+      ClientTransaction state = getTxInternal(xid);
       
       if (state == null)
       {         
@@ -420,11 +370,11 @@
       return xid;
    }
    
-   protected int prepare(Xid xid, ConnectionDelegate connection) throws XAException
+   int prepare(Xid xid, ConnectionDelegate connection) throws XAException
    {
       if (trace) { log.trace("preparing " + xid); }
       
-      TxState state = getTx(xid);
+      ClientTransaction state = getTxInternal(xid);
       
       if (state == null)
       { 
@@ -436,16 +386,16 @@
       
       sendTransactionXA(request, connection);      
       
-      state.setState(TxState.TX_PREPARED);
+      state.setState(ClientTransaction.TX_PREPARED);
       
       return XAResource.XA_OK;
    }
    
-   protected Xid resumeTx(Xid xid) throws XAException
+   Xid resumeTx(Xid xid) throws XAException
    {
       if (trace) { log.trace("resuming " + xid); }
       
-      TxState state = getTx(xid);
+      ClientTransaction state = getTxInternal(xid);
       
       if (state == null)
       {       
@@ -455,11 +405,11 @@
       return xid;
    }
    
-   protected Xid suspendTx(Xid xid) throws XAException
+   Xid suspendTx(Xid xid) throws XAException
    {
       if (trace) { log.trace("suspending " + xid); }
 
-      TxState state = getTx(xid);
+      ClientTransaction state = getTxInternal(xid);
       
       if (state == null)
       {       
@@ -469,48 +419,48 @@
       return xid;
    }
 
-   protected Xid convertTx(LocalTx anonXid, Xid xid) throws XAException
+   Xid convertTx(LocalTx anonXid, Xid xid) throws XAException
    {
       if (trace) { log.trace("converting " + anonXid + " to " + xid); }
 
-      TxState state = getTx(anonXid);
+      ClientTransaction state = getTxInternal(anonXid);
 
       if (state == null)
       {        
          throw new MessagingXAException(XAException.XAER_NOTA, "Cannot find transaction with xid:" + anonXid);
       }
 
-      state = getTx(xid);
+      state = getTxInternal(xid);
 
       if (state != null)
       {        
          throw new MessagingXAException(XAException.XAER_DUPID, "Transaction already exists:" + xid);
       }
 
-      TxState s = removeTx(anonXid);
+      ClientTransaction s = removeTxInternal(anonXid);
       
       transactions.put(xid, s);
       
       return xid;
    }
    
-   protected Xid startTx(Xid xid) throws XAException
+   Xid startTx(Xid xid) throws XAException
    {
       if (trace) { log.trace("starting " + xid); }
 
-      TxState state = getTx(xid);
+      ClientTransaction state = getTxInternal(xid);
       
       if (state != null)
       {
          throw new MessagingXAException(XAException.XAER_DUPID, "Transaction already exists with xid " + xid);
       }
             
-      transactions.put(xid, new TxState());
+      transactions.put(xid, new ClientTransaction());
       
       return xid;
    }
    
-   protected Xid[] recover(int flags, ConnectionDelegate conn) throws XAException
+   Xid[] recover(int flags, ConnectionDelegate conn) throws XAException
    {
       if (trace) { log.trace("calling recover with flags: " + flags); }
       
@@ -532,10 +482,47 @@
       }
    }
    
-   // Package Private ------------------------------------------------
-   
    // Private --------------------------------------------------------
    
+   private ClientTransaction getTxInternal(Object xid)
+   {
+      if (trace) { log.trace("getting transaction for " + xid); }
+      
+      return (ClientTransaction)transactions.get(xid);
+   }
+   
+   private ClientTransaction removeTxInternal(Object xid)
+   {
+      return (ClientTransaction)transactions.remove(xid);
+   }
+   
+   /*
+    * Rollback has occurred so we need to redeliver any unacked messages corresponding to the acks
+    * is in the transaction.
+    */
+   private void redeliverMessages(ClientTransaction ts) throws JMSException
+   {
+      Collection sessionStates = ts.getSessionStates();
+      
+      for (Iterator i = sessionStates.iterator(); i.hasNext();)
+      {
+         SessionTxState state = (SessionTxState)i.next();
+         
+         List acks = state.getAcks();
+         
+         if (!acks.isEmpty())
+         {
+            DeliveryInfo info = (DeliveryInfo)acks.get(0);
+            
+            MessageProxy mp = info.getMessageProxy();
+            
+            SessionDelegate del = mp.getSessionDelegate();
+            
+            del.redeliver(acks);
+         }
+      }
+   }
+   
    private synchronized LocalTx getNextTxId()
    {
       return new LocalTx();

Modified: trunk/src/main/org/jboss/jms/tx/TransactionRequest.java
===================================================================
--- trunk/src/main/org/jboss/jms/tx/TransactionRequest.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/tx/TransactionRequest.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -66,7 +66,7 @@
    /** For 2 phase commit, this identifies the transaction. */
    protected Xid xid;
 
-   protected TxState state;
+   protected ClientTransaction state;
    
    // Static --------------------------------------------------------
    
@@ -76,7 +76,7 @@
    {      
    }
    
-   public TransactionRequest(int requestType, Xid xid, TxState state)
+   public TransactionRequest(int requestType, Xid xid, ClientTransaction state)
    {      
       this.requestType = requestType;
       this.xid = xid;
@@ -153,7 +153,7 @@
      }
      else
      {
-        state = new TxState();
+        state = new ClientTransaction();
      
         state.read(in);
      }
@@ -161,7 +161,7 @@
 
    // Public --------------------------------------------------------
 
-   public TxState getState()
+   public ClientTransaction getState()
    {
       return state;
    }

Deleted: trunk/src/main/org/jboss/jms/tx/TxState.java
===================================================================
--- trunk/src/main/org/jboss/jms/tx/TxState.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/src/main/org/jboss/jms/tx/TxState.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -1,224 +0,0 @@
-/*
- * 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.jms.tx;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import org.jboss.jms.message.JBossMessage;
-import org.jboss.messaging.core.message.MessageFactory;
-import org.jboss.messaging.util.Streamable;
-
-/**
- * Holds information for a JMS transaction to be sent to the server for
- * processing.
- * Holds the messages to be sent and the acknowledgements to be made
- * for the transaction
- * 
- * @author <a href="mailto:tim.fox at jboss.com>Tim Fox </a>
- */
-public class TxState implements Streamable
-{  
-   // Constants -----------------------------------------------------
-
-   public final static byte TX_OPEN = 0;
-   
-   public final static byte TX_ENDED = 1;
-   
-   public final static byte TX_PREPARED = 2;
-   
-   public final static byte TX_COMMITED = 3;
-   
-   public final static byte TX_ROLLEDBACK = 4;
-   
-   // Attributes ----------------------------------------------------
-   
-   protected int state = TX_OPEN;
-   
-   protected List messages = new ArrayList();
-   
-   protected List acks = new ArrayList();
-   
-   // Static --------------------------------------------------------
-   
-   // Constructors --------------------------------------------------
-   
-   public TxState()
-   {      
-   }
-   
-   // Public --------------------------------------------------------
-   
-   public int getState()
-   {
-      return state;
-   }
-   
-   public List getMessages()
-   {
-      return messages;
-   }
-   
-   public List getAcks()
-   {
-      return acks;
-   }
-   
-   public void clearMessages()
-   {
-      messages.clear();
-   }
-   
-   public void setState(int state)
-   {
-      this.state = state;
-   }
-
-
-   /** Navigate on ACK and change consumer ids on every ACK not sent yet */
-   public void handleFailover(int oldConsumerID, int newConsumerID)
-   {
-       for (Iterator ackIterator = acks.iterator(); ackIterator.hasNext(); )
-       {
-           AckInfo ackInfo = (AckInfo)ackIterator.next();
-           
-           if (ackInfo.getConsumerID() == oldConsumerID)
-           {
-               ackInfo.setConsumerID(newConsumerID);
-           }
-       }
-   }
-   
-   public void getAckInfosForConsumerIds(List ackInfos, Set consumerIds)
-   {
-      for (Iterator ackIterator = acks.iterator(); ackIterator.hasNext(); )
-      {
-          AckInfo ackInfo = (AckInfo)ackIterator.next();
-          
-          if (consumerIds.contains(new Integer(ackInfo.getConsumerID())))
-          {
-              ackInfos.add(ackInfo);
-          }
-      }
-   }
-   
-   public void removeNonPersistentAcks(Set consumerIds)
-   {
-      for (Iterator ackIterator = acks.iterator(); ackIterator.hasNext(); )
-      {
-          AckInfo ackInfo = (AckInfo)ackIterator.next();
-          
-          if (!ackInfo.msg.getMessage().isReliable())
-          {
-             ackIterator.remove();
-          }
-      }
-   }
-    
-   // Streamable implementation ---------------------------------
-   
-   public void write(DataOutputStream out) throws Exception
-   {
-      out.writeInt(state);
-      if (messages == null)
-      {
-         out.writeInt(-1);
-      }
-      else
-      {
-         out.writeInt(messages.size());
-         Iterator iter = messages.iterator();
-         while (iter.hasNext())
-         {
-            JBossMessage m = (JBossMessage)iter.next();
-            //We don't use writeObject to avoid serialization overhead
-            out.writeByte(m.getType());
-            m.write(out);
-         } 
-      }
-      if (acks == null)
-      {
-         out.writeInt(-1);
-      }
-      else
-      {
-         out.writeInt(acks.size());
-         Iterator iter = acks.iterator();
-         while (iter.hasNext())
-         {
-            AckInfo a = (AckInfo)iter.next();
-            //We don't use writeObject to avoid serialization overhead
-            a.write(out);
-         }
-      }
-   }
-   
-   public void read(DataInputStream in) throws Exception
-   {
-      state = in.readInt();
-      int numMessages = in.readInt();
-      if (numMessages == -1)
-      {
-         messages = null;
-      }
-      else
-      {
-         messages = new ArrayList(numMessages);
-         for (int i = 0; i < numMessages; i++)
-         {
-            byte type = in.readByte();
-            JBossMessage m = (JBossMessage)MessageFactory.createMessage(type);
-            m.read(in);
-            messages.add(m);
-         }
-      }
-      
-      int numAcks = in.readInt();
-      if (numAcks == -1)
-      {
-         acks = null;
-      }
-      else
-      {
-         acks = new ArrayList(numAcks);
-         for (int i = 0; i < numAcks; i++)
-         {
-            AckInfo info = new AckInfo();
-            info.read(in);
-            acks.add(info);
-         }
-      }  
-   }
-   
-   // Protected -----------------------------------------------------
-   
-   // Package Private -----------------------------------------------
-   
-   // Private -------------------------------------------------------
-      
-   // Inner Classes -------------------------------------------------
-      
-}

Modified: trunk/tests/build.xml
===================================================================
--- trunk/tests/build.xml	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/build.xml	2006-12-14 19:32:42 UTC (rev 1794)
@@ -387,7 +387,7 @@
                     haltonerror="${junit.batchtest.haltonerror}">
             <formatter type="plain" usefile="${junit.formatter.usefile}"/>
             <fileset dir="${build.tests.classes}">
-               <!-- <include name="**/messaging/core/**/*Test.class"/> -->
+               <include name="**/messaging/core/**/*Test.class"/>
                <include name="**/messaging/jms/**/*Test.class"/>
                <exclude name="**/jms/stress/**"/>
                <exclude name="**/jms/crash/*Test.class"/>

Modified: trunk/tests/src/org/jboss/test/messaging/jms/AcknowledgementTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/AcknowledgementTest.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/jms/AcknowledgementTest.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -157,20 +157,14 @@
          pub.publish(m);
          sess.commit();
          
-         log.info("sent messages");
-         
          //receive but rollback
          TextMessage m2 = (TextMessage)sub.receive(3000);
-         
-         log.info("received");
-            
+                
          assertNotNull(m2);
          assertEquals("testing123", m2.getText());
          
          sess.rollback();
          
-         log.info("rolled back");
-         
          conn.close();
          conn = cf.createTopicConnection();
          conn.start();
@@ -262,7 +256,7 @@
       }
    }
    
-   public void testTransactionalAcknowlegment() throws Exception
+   public void testTransactionalAcknowledgement() throws Exception
    {
 
       Connection conn = cf.createConnection();
@@ -328,7 +322,7 @@
       {
          m = consumer.receive();
          log.trace("Received message " + i);
-
+  
       }
       
       assertRemainingMessages(NUM_MESSAGES);
@@ -353,9 +347,8 @@
 	/**
 	 * Send some messages, don't acknowledge them and verify that they are re-sent on recovery.
 	 */
-	public void testClientAcknowledgeNoAcknowlegment() throws Exception
+	public void testClientAcknowledgeNoAcknowledgement() throws Exception
    {
-
 		Connection conn = cf.createConnection();
 
 		Session producerSess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
@@ -1203,7 +1196,10 @@
       Thread.sleep(500);
       ObjectName destObjectName = 
          new ObjectName("jboss.messaging.destination:service=Queue,name=Queue");
-      Integer messageCount = (Integer)ServerManagement.getAttribute(destObjectName, "MessageCount");      
+      Integer messageCount = (Integer)ServerManagement.getAttribute(destObjectName, "MessageCount"); 
+      
+      log.trace("There are " + messageCount + " messages");
+      
       assertEquals(expected, messageCount.intValue());      
       return expected == messageCount.intValue();
    }

Modified: trunk/tests/src/org/jboss/test/messaging/jms/MessageConsumerTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/MessageConsumerTest.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/jms/MessageConsumerTest.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -207,53 +207,64 @@
     */
    public void testRedeliveryToCompetingConsumerOnQueue() throws Exception
    {
-      Connection conn = cf.createConnection();
+      Connection conn = null;
+      
+      try
+      {
+         conn = cf.createConnection();
+      
+         Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+   
+         MessageProducer prod = sessSend.createProducer(queue);
+   
+         conn.start();
+   
+         Session sessConsume1 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+   
+         MessageConsumer cons1 = sessConsume1.createConsumer(queue);
+   
+         TextMessage tm = sessSend.createTextMessage();
+   
+         tm.setText("Your mum");
+   
+         prod.send(tm);
+   
+         TextMessage tm2 = (TextMessage)cons1.receive();
+   
+         assertNotNull(tm2);
+   
+         assertEquals("Your mum", tm2.getText());
+   
+         // Don't ack
+   
+         // Create another consumer
+   
+         Session sessConsume2 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+   
+         MessageConsumer cons2 = sessConsume2.createConsumer(queue);
+   
+         // this should cancel message and cause delivery to other consumer
+   
+         log.trace("Closed session 1");
+         sessConsume1.close();
+   
+         TextMessage tm3 = (TextMessage)cons2.receive(1000);
+   
+         assertNotNull(tm3);
+   
+         assertEquals("Your mum", tm3.getText());
+   
+         tm3.acknowledge();
+      }
+      finally
+      {
 
-      Session sessSend = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         if (conn != null)
+         {
+            conn.close();
+         }
+      }
 
-      MessageProducer prod = sessSend.createProducer(queue);
-
-      conn.start();
-
-      Session sessConsume1 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
-
-      MessageConsumer cons1 = sessConsume1.createConsumer(queue);
-
-      TextMessage tm = sessSend.createTextMessage();
-
-      tm.setText("Your mum");
-
-      prod.send(tm);
-
-      TextMessage tm2 = (TextMessage)cons1.receive();
-
-      assertNotNull(tm2);
-
-      assertEquals("Your mum", tm2.getText());
-
-      // Don't ack
-
-      // Create another consumer
-
-      Session sessConsume2 = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
-
-      MessageConsumer cons2 = sessConsume2.createConsumer(queue);
-
-      // this should cancel message and cause delivery to other consumer
-
-      sessConsume1.close();
-
-      TextMessage tm3 = (TextMessage)cons2.receive(1000);
-
-      assertNotNull(tm3);
-
-      assertEquals("Your mum", tm3.getText());
-
-      tm3.acknowledge();
-
-      conn.close();
-
-
    }
 
 

Modified: trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/jms/WireFormatTest.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -31,6 +31,7 @@
 import java.io.Serializable;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -43,12 +44,16 @@
 import org.jboss.jms.delegate.SessionDelegate;
 import org.jboss.jms.message.JBossMessage;
 import org.jboss.jms.message.MessageProxy;
+import org.jboss.jms.server.endpoint.Ack;
+import org.jboss.jms.server.endpoint.Cancel;
 import org.jboss.jms.server.endpoint.ClientDelivery;
+import org.jboss.jms.server.endpoint.DefaultAck;
+import org.jboss.jms.server.endpoint.DeliveryInfo;
 import org.jboss.jms.server.remoting.JMSWireFormat;
 import org.jboss.jms.server.remoting.MessagingMarshallable;
-import org.jboss.jms.tx.AckInfo;
+import org.jboss.jms.tx.ClientTransaction;
 import org.jboss.jms.tx.TransactionRequest;
-import org.jboss.jms.tx.TxState;
+import org.jboss.jms.tx.ClientTransaction.SessionTxState;
 import org.jboss.logging.Logger;
 import org.jboss.messaging.core.plugin.IdBlock;
 import org.jboss.remoting.InvocationRequest;
@@ -130,11 +135,13 @@
       
       sendMethod = sessionDelegate.getMethod("send", new Class[] { JBossMessage.class });
        
-      acknowledgeMethod = sessionDelegate.getMethod("acknowledge", new Class[] { AckInfo.class });
+      acknowledgeMethod = sessionDelegate.getMethod("acknowledge", new Class[] { Ack.class });
       
       acknowledgeBatchMethod = sessionDelegate.getMethod("acknowledgeBatch", new Class[] { java.util.List.class });
       
       cancelDeliveriesMethod = sessionDelegate.getMethod("cancelDeliveries", new Class[] { java.util.List.class });
+      
+      //TODO - this isn't complete - there are other methods to test
             
       //Consumer
             
@@ -263,10 +270,8 @@
          
          mi.getMetaData().addMetaData(Dispatcher.DISPATCHER, Dispatcher.OID, new Integer(objectId));   
          
-         long messageID = 123456;
-         int consumerID = 65432;
-         int deliveryCount = 765;
-         AckInfo ack = new AckInfo(messageID, consumerID, deliveryCount);
+         int deliveryID = 765;
+         Ack ack = new DefaultAck(deliveryID);
          
          Object[] args = new Object[] { ack };
          
@@ -304,15 +309,11 @@
          //Next long should be methodHash
          assertEquals(methodHash, dis.readLong());
          
-         //Next should be the externalized AckInfo
-         AckInfo ack2 = new AckInfo();
-                  
-         ack2.read(dis);
+         //Next should be the deliveryid
+         long l = dis.readLong();
          
-         assertEquals(ack.getMessageID(), ack2.getMessageID());
-         assertEquals(ack.getConsumerID(), ack2.getConsumerID());
-         assertEquals(ack.getDeliveryCount(), ack2.getDeliveryCount());
-         
+         assertEquals(deliveryID, l);
+
          //Now eos
          try
          {
@@ -340,10 +341,9 @@
          
          assertEquals(objectId, ((Integer)mi2.getMetaData().getMetaData(Dispatcher.DISPATCHER, Dispatcher.OID)).intValue());
          
-         AckInfo ack3 = (AckInfo)mi2.getArguments()[0];
+         Ack l2 = (Ack)mi2.getArguments()[0];
          
-         assertEquals(ack3.getMessageID(), ack3.getMessageID());
-         assertEquals(ack3.getConsumerID(), ack3.getConsumerID());
+         assertEquals(deliveryID, l2.getDeliveryId());
          
       }
       
@@ -357,14 +357,16 @@
          
          mi.getMetaData().addMetaData(Dispatcher.DISPATCHER, Dispatcher.OID, new Integer(objectId));   
          
-         AckInfo ackA = new AckInfo(1524, 71627, 32);
-         AckInfo ackB = new AckInfo(987987, 45354, 21);
-         AckInfo ackC = new AckInfo(32423, 4533, 6);
+         long ackA = 1343;
          
+         long ackB = 176276;
+         
+         long ackC = 17261726;
+                  
          List acks = new ArrayList();
-         acks.add(ackA);
-         acks.add(ackB);
-         acks.add(ackC);
+         acks.add(new DefaultAck(ackA));
+         acks.add(new DefaultAck(ackB));
+         acks.add(new DefaultAck(ackC));
          
          Object[] args = new Object[] { acks };
          
@@ -406,31 +408,17 @@
          assertEquals(3, dis.readInt());
          
          //Now the acks
-         AckInfo ack = new AckInfo();
-            
-         ack.read(dis);
+         long l1 = dis.readLong();
          
-         assertEquals(ackA.getMessageID(), ack.getMessageID());
-         assertEquals(ackA.getConsumerID(), ack.getConsumerID());
-         assertEquals(ackA.getDeliveryCount(), ack.getDeliveryCount());
+         long l2 = dis.readLong();
          
-         ack = new AckInfo();
+         long l3 = dis.readLong();
          
-         ack.read(dis);
+         assertEquals(ackA, l1);
+         assertEquals(ackB, l2);
+         assertEquals(ackC, l3);
          
-         assertEquals(ackB.getMessageID(), ack.getMessageID());
-         assertEquals(ackB.getConsumerID(), ack.getConsumerID());
-         assertEquals(ackB.getDeliveryCount(), ack.getDeliveryCount());
          
-         ack = new AckInfo();
-         
-         ack.read(dis);
-         
-         assertEquals(ackC.getMessageID(), ack.getMessageID());
-         assertEquals(ackC.getConsumerID(), ack.getConsumerID());
-         assertEquals(ackC.getDeliveryCount(), ack.getDeliveryCount());
-         
-         
          //Now eos
          try
          {
@@ -462,14 +450,10 @@
          
          assertEquals(3, acks.size());
          
-         assertEquals(ackA.getMessageID(), ((AckInfo)(acks2.get(0))).getMessageID());
-         assertEquals(ackA.getConsumerID(), ((AckInfo)(acks2.get(0))).getConsumerID());
+         assertEquals(ackA, ((DefaultAck)acks2.get(0)).getDeliveryId());
+         assertEquals(ackB, ((DefaultAck)acks2.get(1)).getDeliveryId());
+         assertEquals(ackC, ((DefaultAck)acks2.get(2)).getDeliveryId());
          
-         assertEquals(ackB.getMessageID(), ((AckInfo)(acks2.get(1))).getMessageID());
-         assertEquals(ackB.getConsumerID(), ((AckInfo)(acks2.get(1))).getConsumerID());
-         
-         assertEquals(ackC.getMessageID(), ((AckInfo)(acks2.get(2))).getMessageID());
-         assertEquals(ackC.getConsumerID(), ((AckInfo)(acks2.get(2))).getConsumerID());
       }
       
       
@@ -739,11 +723,19 @@
          JBossMessage m = new JBossMessage(123);
          MessageTest.configureMessage(m);
          
-         AckInfo info = new AckInfo(123, 456, 66);
+         long deliveryId = 89281389;
          
-         TxState state = new TxState();
-         state.getMessages().add(m);
-         state.getAcks().add(info);
+         int deliveryCount = 12;
+         
+         MessageProxy proxy = JBossMessage.createThinDelegate(deliveryId, m, deliveryCount);
+                     
+         DeliveryInfo info = new DeliveryInfo(proxy, 76762, 98982);
+         
+         int sessionId = 8787;
+         
+         ClientTransaction state = new ClientTransaction();
+         state.addMessage(sessionId, m);
+         state.addAck(sessionId, info);
           
          TransactionRequest request = new TransactionRequest(TransactionRequest.ONE_PHASE_COMMIT_REQUEST, null, state);
                            
@@ -806,18 +798,24 @@
          {
             //Ok
          }
+         
+         ClientTransaction state2 = req.getState();
+         
+         Collection sessionStates = state2.getSessionStates();
+         
+         assertEquals(1, sessionStates.size());
+         
+         SessionTxState sess = (SessionTxState)sessionStates.iterator().next();
 
-         JBossMessage m2 = (JBossMessage)req.getState().getMessages().get(0);
+         JBossMessage m2 = (JBossMessage)sess.getMsgs().get(0);
          
          MessageTest.ensureEquivalent(m, m2);
          
          assertEquals(TransactionRequest.ONE_PHASE_COMMIT_REQUEST, req.getRequestType());
          
-         AckInfo info2 = (AckInfo)req.getState().getAcks().get(0);
+         Ack ack = (Ack)sess.getAcks().get(0);
          
-         assertEquals(info.getConsumerID(), info2.getConsumerID());
-         assertEquals(info.getMessageID(), info2.getMessageID());
-         assertEquals(info.getDeliveryCount(), info2.getDeliveryCount());
+         assertEquals(deliveryId, ack.getDeliveryId());
          
          bis.reset();
          
@@ -837,17 +835,22 @@
          
          TransactionRequest req2 = (TransactionRequest)mi2.getArguments()[0];
          
-         JBossMessage m3 = (JBossMessage)req2.getState().getMessages().get(0);
+         ClientTransaction state3 = req2.getState();
          
+         Collection sessionStates2 = state3.getSessionStates();
+         
+         SessionTxState sess2 = (SessionTxState)sessionStates2.iterator().next();
+         
+         JBossMessage m3 = (JBossMessage)sess2.getMsgs().get(0);
+         
          MessageTest.ensureEquivalent(m, m3);
          
          assertEquals(TransactionRequest.ONE_PHASE_COMMIT_REQUEST, req2.getRequestType());
          
-         AckInfo info3 = (AckInfo)req2.getState().getAcks().get(0);
+         Ack ack2 = (Ack)sess2.getAcks().get(0);
          
-         assertEquals(info.getConsumerID(), info3.getConsumerID());
-         assertEquals(info.getMessageID(), info3.getMessageID());
-                  
+         assertEquals(deliveryId, ack2.getDeliveryId());
+         
       }  
             
       
@@ -857,18 +860,18 @@
          
          int objectId = 54321;
          
-         List ids = new ArrayList();
+         List cancels = new ArrayList();
          
-         AckInfo ack1 = new AckInfo(1254, 78123, 22);
-         AckInfo ack2 = new AckInfo(786, 8979, 461);
-         ids.add(ack1);
-         ids.add(ack2);
+         Cancel cancel1 = new Cancel(65654, 43);
+         Cancel cancel2 = new Cancel(65765, 2);
+         cancels.add(cancel1);
+         cancels.add(cancel2);
          
          MethodInvocation mi = new MethodInvocation(null, methodHash, cancelDeliveriesMethod, cancelDeliveriesMethod, null);
          
          mi.getMetaData().addMetaData(Dispatcher.DISPATCHER, Dispatcher.OID, new Integer(objectId));   
          
-         mi.setArguments(new Object[] {ids});
+         mi.setArguments(new Object[] {cancels});
          
          MessagingMarshallable mm = new MessagingMarshallable((byte)77, mi);
          
@@ -909,27 +912,22 @@
          assertEquals(2, size);
          
          //then the AckInfos
-         AckInfo rack1 = new AckInfo();
+         Cancel rcancel1 = new Cancel();
          
-         AckInfo rack2 = new AckInfo();
+         Cancel rcancel2 = new Cancel();
          
-         rack1.read(dis);
+         rcancel1.read(dis);
          
-         rack2.read(dis);
+         rcancel2.read(dis);
          
-         assertEquals(ack1.getConsumerID(), rack1.getConsumerID());
+         assertEquals(cancel1.getDeliveryCount(), rcancel1.getDeliveryCount());
          
-         assertEquals(ack1.getMessageID(), rack1.getMessageID());
+         assertEquals(cancel1.getDeliveryId(), cancel1.getDeliveryId());
          
-         assertEquals(ack1.getDeliveryCount(), rack1.getDeliveryCount());
+         assertEquals(cancel2.getDeliveryCount(), rcancel2.getDeliveryCount());
          
-         assertEquals(ack2.getConsumerID(), rack2.getConsumerID());
-         
-         assertEquals(ack2.getMessageID(), rack2.getMessageID());
-         
-         assertEquals(ack2.getDeliveryCount(), rack2.getDeliveryCount());
-         
-          
+         assertEquals(cancel2.getDeliveryId(), cancel2.getDeliveryId());
+                   
          //should be eos
                 
          try
@@ -963,16 +961,17 @@
         
          assertEquals(2, list.size());
          
-         AckInfo xack1 = (AckInfo)list.get(0);
-         AckInfo xack2 = (AckInfo)list.get(1);
+         Cancel xack1 = (Cancel)list.get(0);
+         Cancel xack2 = (Cancel)list.get(1);
          
-         assertEquals(ack1.getConsumerID(), xack1.getConsumerID());
+         assertEquals(cancel1.getDeliveryId(), xack1.getDeliveryId());
          
-         assertEquals(ack1.getMessageID(), xack1.getMessageID());
+         assertEquals(cancel1.getDeliveryCount(), xack1.getDeliveryCount());
          
-         assertEquals(ack2.getConsumerID(), xack2.getConsumerID());
+         assertEquals(cancel2.getDeliveryId(), xack2.getDeliveryId());
          
-         assertEquals(ack2.getMessageID(), xack2.getMessageID());
+         assertEquals(cancel2.getDeliveryCount(), xack2.getDeliveryCount());
+         
       }  
       
       public void testNullResponse() throws Exception
@@ -1100,17 +1099,15 @@
       {
          int consumerID = 12345678;
          
-         int serverId = 76543;
-         
          JBossMessage m1 = new JBossMessage(123);
          JBossMessage m2 = new JBossMessage(456);
          JBossMessage m3 = new JBossMessage(789);
          
          List msgs = new ArrayList();
          
-         MessageProxy del1 = JBossMessage.createThinDelegate(m1, 7);
-         MessageProxy del2 = JBossMessage.createThinDelegate(m2, 8);
-         MessageProxy del3 = JBossMessage.createThinDelegate(m3, 9);
+         MessageProxy del1 = JBossMessage.createThinDelegate(1, m1, 7);
+         MessageProxy del2 = JBossMessage.createThinDelegate(2, m2, 8);
+         MessageProxy del3 = JBossMessage.createThinDelegate(3, m3, 9);
          
          MessageTest.configureMessage(m1);
          MessageTest.configureMessage(m2);
@@ -1120,7 +1117,7 @@
          msgs.add(del2);
          msgs.add(del3);         
          
-         ClientDelivery dr = new ClientDelivery(msgs, serverId, consumerID);
+         ClientDelivery dr = new ClientDelivery(msgs, consumerID);
          
          ByteArrayOutputStream bos = new ByteArrayOutputStream();
          
@@ -1149,23 +1146,21 @@
          //Next should be sessionID
          assertEquals("dummySessionId", dis.readUTF());
          
-         //Next int should be server id
-         assertEquals(76543, dis.readInt());
-         
          //Next int should be consumer id
          assertEquals(12345678, dis.readInt());
          
          //Next int should be number of messages
          assertEquals(3, dis.readInt());
-         
-         
-         
+                           
          //Next byte should be type
          assertEquals(JBossMessage.TYPE, dis.readByte());
          
          //Next int should be delivery count
          assertEquals(7, dis.readInt());
          
+         //Delivery id
+         assertEquals(1, dis.readLong());
+         
          //And now the message itself
          JBossMessage r1 = new JBossMessage();
          
@@ -1178,6 +1173,9 @@
          //Next int should be delivery count
          assertEquals(8, dis.readInt());
          
+         // Delivery id
+         assertEquals(2, dis.readLong());
+         
          //And now the message itself
          JBossMessage r2 = new JBossMessage();
          
@@ -1190,6 +1188,9 @@
          //Next int should be delivery count
          assertEquals(9, dis.readInt());
          
+         // Delivery id
+         assertEquals(3, dis.readLong());
+         
          //And now the message itself
          JBossMessage r3 = new JBossMessage();
          
@@ -1232,7 +1233,6 @@
          
          List msgs2 = dr2.getMessages();
          
-         assertEquals(serverId, dr2.getServerId());
          assertEquals(consumerID, dr2.getConsumerId());
          
          MessageProxy p1 = (MessageProxy)msgs2.get(0);

Modified: trunk/tests/src/org/jboss/test/messaging/jms/clustering/HATest.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/jms/clustering/HATest.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/jms/clustering/HATest.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -113,15 +113,15 @@
       
       try
       {         
-         conn1 = factory.createConnection();
+         conn1 = factory.createConnection();  //server 0
          
-         conn2 = factory.createConnection();
+         conn2 = factory.createConnection();  //server 1
          
-         conn3 = factory.createConnection();
+         conn3 = factory.createConnection();  //server 2
          
-         conn4 = factory.createConnection();
+         conn4 = factory.createConnection();  //server 0
          
-         conn5 = factory.createConnection();
+         conn5 = factory.createConnection();  //server 1
          
          ConnectionState state1 = (ConnectionState)(((DelegateSupport)((JBossConnection)conn1).getDelegate()).getState());
          
@@ -441,6 +441,8 @@
       int server1Id = cf2.getServerID();
       
       int server2Id = cf3.getServerID();
+
+      //Server order should be 2, 0, 1
       
       log.info("server 0 id: " + server0Id);
       
@@ -462,15 +464,19 @@
       
       Connection conn = null;
       
+      boolean killed =  false;
+            
       try
-      {
-      
-         //Get a connection on server 1
+      {      
+         conn = factory.createConnection(); //connection on server 2
+         
+         conn.close();
+         
          conn = factory.createConnection(); //connection on server 0
          
          conn.close();
          
-         conn = factory.createConnection(); //connection on server 1
+         conn = factory.createConnection(); // connection on server 1
          
          JBossConnection jbc = (JBossConnection)conn;
          
@@ -505,6 +511,8 @@
          
          ServerManagement.kill(1);
          
+         killed = true;
+         
          log.info("killed server, now waiting");
          
          Thread.sleep(5000);
@@ -546,8 +554,14 @@
             catch (Exception e)
             {
                e.printStackTrace();
-            }
+            }         
          }
+         
+         //Resurrect dead server
+         if (killed)
+         {
+            ServerManagement.spawn(1);
+         }
       }
       
    }
@@ -597,14 +611,15 @@
       
       Connection conn = null;
       
+      boolean killed = false;
+      
       try
       {      
-         //Get a connection on server 1
-         conn = factory.createConnection(); //connection on server 0
+         conn = factory.createConnection(); //connection on server 1
          
          conn.close();
          
-         conn = factory.createConnection(); //connection on server 1
+         conn = factory.createConnection(); //connection on server 2
          
          JBossConnection jbc = (JBossConnection)conn;
          
@@ -614,7 +629,7 @@
          
          int initialServerID = state.getServerID();
          
-         assertEquals(1, initialServerID);
+         assertEquals(2, initialServerID);
                            
          Session sess = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE);
          
@@ -653,9 +668,11 @@
          
          ServerManagement.kill(1);
          
+         killed = true;
+         
          log.info("killed server, now waiting");
          
-         Thread.sleep(5000);
+         Thread.sleep(10000);
          
          log.info("done wait");
          
@@ -720,6 +737,12 @@
                e.printStackTrace();
             }
          }
+         
+         // Resurrect dead server
+         if (killed)
+         {
+            ServerManagement.spawn(1);
+         }
       }
       
    }
@@ -768,6 +791,8 @@
       
       Connection conn = null;
       
+      boolean killed = false;
+      
       try
       {      
          //Get a connection on server 1
@@ -825,6 +850,8 @@
          log.info("************ KILLING (CRASHING) SERVER 1");
          
          ServerManagement.kill(1);
+         
+         killed = true;
 
          log.info("killed server, now waiting");
          
@@ -893,51 +920,16 @@
                e.printStackTrace();
             }
          }
+         
+         if (killed)
+         {
+            ServerManagement.spawn(1);
+         }
       }
       
    }
    
    
-   
-   
-//   public void testEvenSimplerFailover() throws Exception
-//   {
-//      JBossConnectionFactory factory =  (JBossConnectionFactory )ic[0].lookup("/ConnectionFactory");
-//                  
-//      Connection conn = null;
-//      
-//      try
-//      {
-//         conn = factory.createConnection();
-//                           
-//         log.info("************ KILLING (CRASHING) SERVER 0");
-//         
-//         ServerManagement.getServer(0).destroy();
-//         
-//         log.info("killed server, now waiting");
-//         
-//         Thread.sleep(25000);
-//         
-//         log.info("done wait");                
-//      }
-//      finally
-//      {         
-//         if (conn != null)
-//         {
-//            try
-//            {
-//               conn.close();
-//            }
-//            catch (Exception e)
-//            {
-//               e.printStackTrace();
-//            }
-//         }
-//      }
-//      
-//   }
-   
-   
 // public void testConnectionFactoryConnect() throws Exception
 // {
 // try

Modified: trunk/tests/src/org/jboss/test/messaging/tools/jboss/MBeanConfigurationElement.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/tools/jboss/MBeanConfigurationElement.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/tools/jboss/MBeanConfigurationElement.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -11,6 +11,8 @@
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 import org.jboss.jms.util.XMLUtil;
+import org.jboss.logging.Logger;
+import org.jboss.test.messaging.tools.jmx.rmi.LocalTestServer;
 
 import javax.management.ObjectName;
 import java.util.Map;
@@ -30,7 +32,10 @@
 public class MBeanConfigurationElement
  {
    // Constants -----------------------------------------------------
+   
+   private static final Logger log = Logger.getLogger(MBeanConfigurationElement.class);
 
+
    // Static --------------------------------------------------------
 
    public static Class stringToClass(String type) throws Exception
@@ -82,6 +87,8 @@
 
       Node mbeanNameAttr = attrs.getNamedItem("name");
       on = new ObjectName(mbeanNameAttr.getNodeValue());
+      
+      log.trace("ObjectName is: " + on);
 
       Node mbeanCodeAttr = attrs.getNamedItem("code");
       className = mbeanCodeAttr.getNodeValue();

Modified: trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java
===================================================================
--- trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java	2006-12-14 16:02:46 UTC (rev 1793)
+++ trunk/tests/src/org/jboss/test/messaging/tools/jmx/rmi/LocalTestServer.java	2006-12-14 19:32:42 UTC (rev 1794)
@@ -728,6 +728,8 @@
                                        int defaultTempQueuePageSize,
                                        int defaultTempQueueDownCacheSize) throws Exception
    {
+      log.trace("deploying connection factory with name: " + objectName);
+      
       String config =
          "<mbean code=\"org.jboss.jms.server.connectionfactory.ConnectionFactory\"\n" +
                 "name=\"" + objectName + "\"\n" +
@@ -766,6 +768,9 @@
 
       MBeanConfigurationElement mc = new MBeanConfigurationElement(XMLUtil.stringToElement(config));
       ObjectName on = sc.registerAndConfigureService(mc);
+      
+      log.trace("Object name is now: " + on);
+      
       sc.invoke(on, "create", new Object[0], new String[0]);
       sc.invoke(on, "start", new Object[0], new String[0]);
    }




More information about the jboss-cvs-commits mailing list