[jboss-cvs] JBoss Messaging SVN: r3371 - in branches/Branch_Stable: src/main/org/jboss/jms/client/remoting and 4 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Tue Nov 27 14:43:02 EST 2007


Author: timfox
Date: 2007-11-27 14:43:01 -0500 (Tue, 27 Nov 2007)
New Revision: 3371

Added:
   branches/Branch_Stable/src/main/org/jboss/messaging/util/Reorderer.java
   branches/Branch_Stable/tests/src/org/jboss/test/messaging/util/ReordererTest.java
Modified:
   branches/Branch_Stable/src/main/org/jboss/jms/client/container/ClientConsumer.java
   branches/Branch_Stable/src/main/org/jboss/jms/client/container/ConsumerAspect.java
   branches/Branch_Stable/src/main/org/jboss/jms/client/remoting/CallbackManager.java
   branches/Branch_Stable/src/main/org/jboss/jms/client/state/SessionState.java
   branches/Branch_Stable/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java
Log:
http://jira.jboss.org/jira/browse/JBMESSAGING-1166


Modified: branches/Branch_Stable/src/main/org/jboss/jms/client/container/ClientConsumer.java
===================================================================
--- branches/Branch_Stable/src/main/org/jboss/jms/client/container/ClientConsumer.java	2007-11-27 13:19:26 UTC (rev 3370)
+++ branches/Branch_Stable/src/main/org/jboss/jms/client/container/ClientConsumer.java	2007-11-27 19:43:01 UTC (rev 3371)
@@ -35,10 +35,13 @@
 import org.jboss.jms.delegate.DefaultCancel;
 import org.jboss.jms.delegate.DeliveryInfo;
 import org.jboss.jms.delegate.SessionDelegate;
+import org.jboss.jms.message.JBossMessage;
 import org.jboss.jms.message.MessageProxy;
+import org.jboss.jms.wireformat.ClientDelivery;
 import org.jboss.logging.Logger;
 import org.jboss.messaging.core.contract.Message;
 import org.jboss.messaging.util.Future;
+import org.jboss.messaging.util.Reorderer;
 import org.jboss.messaging.util.prioritylinkedlist.BasicPriorityLinkedList;
 import org.jboss.messaging.util.prioritylinkedlist.PriorityLinkedList;
 
@@ -216,7 +219,8 @@
    private boolean handleFlowControl;
    private long redeliveryDelay;
    private volatile int currentToken;
-   
+   private Reorderer reorderer;
+     
    // Constructors ---------------------------------------------------------------------------------
 
    public ClientConsumer(boolean isCC, int ackMode,                                
@@ -224,7 +228,7 @@
                          String queueName,
                          int bufferSize, QueuedExecutor sessionExecutor,
                          int maxDeliveries, boolean shouldAck, boolean handleFlowControl,
-                         long redeliveryDelay)
+                         long redeliveryDelay, Reorderer reorderer)
    {
       if (bufferSize < 1)
       {
@@ -246,11 +250,14 @@
       this.shouldAck = shouldAck;
       this.handleFlowControl = handleFlowControl;
       this.redeliveryDelay = redeliveryDelay;
+      this.reorderer = reorderer;
    }
         
    // Public ---------------------------------------------------------------------------------------
 
 
+   
+   
    public boolean isClosed()
    {
       return closed;
@@ -263,12 +270,24 @@
     */
    public void handleMessage(final Object message) throws Exception
    {
+      ClientDelivery del = (ClientDelivery)message;
+      
+      //We need to make sure the deliveries are in the right order - 
+      //Due to the way remoting pooling works we cannot guarantee invocations will use the same TCP connection
+      //Therefore they can be delivered out of order.
+      //We therefore need to re-order them on arrival
+       
+      Message msg = del.getMessage();
+      
+      MessageProxy proxy = JBossMessage.
+         createThinDelegate(del.getDeliveryId(), (JBossMessage)msg, del.getDeliveryCount());
+
       //TODO - we temporarily need to execute on a different thread to avoid a deadlock situation in
       //       failover where a message is sent then the valve is locked, and the message send cause
       //       a message delivery back to the same client which tries to ack but can't get through
       //       the valve. This won't be necessary when we move to a non blocking transport
-   	
-      sessionExecutor.execute(new HandleMessageRunnable(currentToken, message));         
+      
+      reorderer.handle(new HandleMessageRunnable(currentToken, proxy), del.getDeliveryId());
    }
    
    public void setMessageListener(MessageListener listener) throws JMSException
@@ -860,21 +879,19 @@
    {
    	private int token;
    	
-   	private Object message;
+   	private MessageProxy proxy;
    	
-   	HandleMessageRunnable(int token, Object message)
+   	HandleMessageRunnable(int token, MessageProxy proxy)
    	{
    		this.token = token;
    		
-   		this.message = message;
+   		this.proxy = proxy;
    	}
    	
    	public void run()
       {
          try
          {
-         	 MessageProxy proxy = (MessageProxy) message;
-
              if (trace) { log.trace(this + " receiving message " + proxy + " from the remoting layer"); }
 
              synchronized (mainLock)
@@ -889,7 +906,7 @@
                 if (token != currentToken)
                 {
                	 //This message was queued up from before failover - we don't want to add it
-               	 log.trace("Ignoring message " + message);
+               	 log.trace("Ignoring message " + proxy);
                	 return;
                 }
                 
@@ -1000,7 +1017,7 @@
          
          if (trace) { log.trace("Exiting run()"); }
       }
-   }   
+   }         
 }
 
 

Modified: branches/Branch_Stable/src/main/org/jboss/jms/client/container/ConsumerAspect.java
===================================================================
--- branches/Branch_Stable/src/main/org/jboss/jms/client/container/ConsumerAspect.java	2007-11-27 13:19:26 UTC (rev 3370)
+++ branches/Branch_Stable/src/main/org/jboss/jms/client/container/ConsumerAspect.java	2007-11-27 19:43:01 UTC (rev 3371)
@@ -36,6 +36,7 @@
 import org.jboss.jms.exception.MessagingShutdownException;
 import org.jboss.logging.Logger;
 import org.jboss.messaging.util.MessageQueueNameHelper;
+import org.jboss.messaging.util.Reorderer;
 
 import EDU.oswego.cs.dl.util.concurrent.QueuedExecutor;
 
@@ -83,6 +84,7 @@
       String consumerID = consumerState.getConsumerID();
       int prefetchSize = consumerState.getBufferSize();
       QueuedExecutor sessionExecutor = sessionState.getExecutor();
+      Reorderer reorderer = sessionState.getReorderer();
       int maxDeliveries = consumerState.getMaxDeliveries();
       long redeliveryDelay = consumerState.getRedeliveryDelay();
       
@@ -110,7 +112,7 @@
          new ClientConsumer(isCC, sessionState.getAcknowledgeMode(),
                             sessionDelegate, consumerDelegate, consumerID, queueName,
                             prefetchSize, sessionExecutor, maxDeliveries, consumerState.isShouldAck(),
-                            autoFlowControl, redeliveryDelay);
+                            autoFlowControl, redeliveryDelay, reorderer);
       
       sessionState.addCallbackHandler(messageHandler);
       

Modified: branches/Branch_Stable/src/main/org/jboss/jms/client/remoting/CallbackManager.java
===================================================================
--- branches/Branch_Stable/src/main/org/jboss/jms/client/remoting/CallbackManager.java	2007-11-27 13:19:26 UTC (rev 3370)
+++ branches/Branch_Stable/src/main/org/jboss/jms/client/remoting/CallbackManager.java	2007-11-27 19:43:01 UTC (rev 3371)
@@ -84,11 +84,6 @@
       {
          ClientDelivery dr = (ClientDelivery)parameter;
           
-         Message msg = dr.getMessage();
-         
-         MessageProxy proxy = JBossMessage.
-            createThinDelegate(dr.getDeliveryId(), (JBossMessage)msg, dr.getDeliveryCount());
-
          ClientConsumer handler =
             (ClientConsumer)callbackHandlers.get(dr.getConsumerId());
 
@@ -102,7 +97,7 @@
 
          try
          {
-            handler.handleMessage(proxy);
+            handler.handleMessage(dr);
          }
          catch (Exception e)
          {

Modified: branches/Branch_Stable/src/main/org/jboss/jms/client/state/SessionState.java
===================================================================
--- branches/Branch_Stable/src/main/org/jboss/jms/client/state/SessionState.java	2007-11-27 13:19:26 UTC (rev 3370)
+++ branches/Branch_Stable/src/main/org/jboss/jms/client/state/SessionState.java	2007-11-27 19:43:01 UTC (rev 3371)
@@ -47,6 +47,7 @@
 import org.jboss.jms.tx.ResourceManager;
 import org.jboss.logging.Logger;
 import org.jboss.messaging.util.ClearableQueuedExecutor;
+import org.jboss.messaging.util.Reorderer;
 import org.jboss.messaging.util.Version;
 
 import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;
@@ -111,6 +112,8 @@
    
    private long npSendSequence;
    
+   private Reorderer reorderer;
+   
    // Constructors ---------------------------------------------------------------------------------
 
    public SessionState(ConnectionState parent, ClientSessionDelegate delegate,
@@ -150,6 +153,8 @@
       // TODO could optimise this to use the same map of callbackmanagers (which holds refs
       // to callbackhandlers) in the connection, instead of maintaining another map
       callbackHandlers = new HashMap();
+      
+      this.reorderer = new ReceiveReorderer();
    }
 
    // HierarchicalState implementation -------------------------------------------------------------
@@ -344,20 +349,26 @@
                                     del.getMessageProxy().getMessage().getMessageID(),
                                     del.getQueueName());
 
-            recoveryInfos.add(recInfo);
+            recoveryInfos.add(recInfo);         
          }         
       }
-
-      //Note! We ALWAYS call recoverDeliveries even if there are no deliveries since it also does other stuff
-      //like remove from recovery Area refs corresponding to messages in client consumer buffers
       
       log.trace(this + " sending delivery recovery " + recoveryInfos + " on failover");
       
       //Note we only recover sessions that are transacted or client ack
       if (transacted || xa || acknowledgeMode == Session.CLIENT_ACKNOWLEDGE)
       {
+         //Note! We ALWAYS call recoverDeliveries even if there are no deliveries since it also does other stuff
+         //like remove from recovery Area refs corresponding to messages in client consumer buffers
+         
       	newDelegate.recoverDeliveries(recoveryInfos, oldSessionID);
       }
+      else
+      {
+         //The delivery id will get reset so we must reset on the re-orderer too
+         
+         reorderer.reset();
+      }
    }
    
    // Public ---------------------------------------------------------------------------------------
@@ -475,6 +486,11 @@
    	npSendSequence++;
    }
    
+   public Reorderer getReorderer()
+   {
+      return reorderer;
+   }
+   
    public String toString()
    {
       return "SessionState[" + sessionID + "]";
@@ -487,6 +503,14 @@
    // Private --------------------------------------------------------------------------------------
 
    // Inner classes --------------------------------------------------------------------------------
+   
+   private class ReceiveReorderer extends Reorderer
+   {
+      public void execute(Object object) throws Exception
+      {         
+         executor.execute((Runnable)object);   
+      }
+   }
 
 }
 

Modified: branches/Branch_Stable/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java
===================================================================
--- branches/Branch_Stable/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java	2007-11-27 13:19:26 UTC (rev 3370)
+++ branches/Branch_Stable/src/main/org/jboss/jms/server/endpoint/ServerSessionEndpoint.java	2007-11-27 19:43:01 UTC (rev 3371)
@@ -86,6 +86,7 @@
 import org.jboss.messaging.util.ExceptionUtil;
 import org.jboss.messaging.util.GUIDGenerator;
 import org.jboss.messaging.util.MessageQueueNameHelper;
+import org.jboss.messaging.util.Reorderer;
 import org.jboss.remoting.Client;
 import org.jboss.remoting.callback.Callback;
 import org.jboss.remoting.callback.ServerInvokerCallbackHandler;
@@ -128,8 +129,6 @@
    
    private static final long DELIVERY_WAIT_TIMEOUT = 5 * 1000;
    
-   private static final long CLOSE_WAIT_TIMEOUT = 5 * 1000;
-      
    // Static ---------------------------------------------------------------------------------------
 
    // Attributes -----------------------------------------------------------------------------------
@@ -168,17 +167,17 @@
    // Map <deliveryID, Delivery>
    private Map deliveries;
    
-   private SynchronizedLong deliveryIdSequence;
+   private long deliveryIdSequence;
    
    //Temporary until we have our own NIO transport   
    QueuedExecutor executor = new QueuedExecutor(new LinkedQueue());
    
    private LinkedQueue toDeliver = new LinkedQueue();
    
+   private Reorderer reorderer = new SendReorderer();
+      
    private boolean waitingToClose = false;
    
-   private Object waitLock = new Object();
-   
    // Constructors ---------------------------------------------------------------------------------
 
    ServerSessionEndpoint(String sessionID, ServerConnectionEndpoint connectionEndpoint,
@@ -225,8 +224,6 @@
       defaultRedeliveryDelay = sp.getDefaultRedeliveryDelay();
       
       deliveries = new ConcurrentHashMap();
-      
-      deliveryIdSequence = new SynchronizedLong(0);
    }
    
    // SessionDelegate implementation ---------------------------------------------------------------
@@ -344,77 +341,24 @@
       
       if (sequence != 0)
       {
-      	synchronized (waitLock)
-      	{      		
-      		long wait = CLOSE_WAIT_TIMEOUT;
-      		
-	      	while (sequence != expectedSequence && wait > 0)
-	      	{
-	      		long start = System.currentTimeMillis(); 
-	      		try
-	      		{
-	      			waitLock.wait();
-	      		}
-	      		catch (InterruptedException e)
-	      		{	      			
-	      		}
-	      		wait -= (System.currentTimeMillis() - start);
-	      	}
-	      	
-	      	if (wait <= 0)
-	      	{
-	      		log.warn("Timed out waiting for last message");
-	      	}
-      	}      	
+      	reorderer.waitToArrive(sequence); 	
       }      
       
       return -1;
    }
  
-   private volatile long expectedSequence = 0;
-   
-   private Map<Long, JBossMessage> heldBack = new HashMap<Long, JBossMessage>();
-   
    public void send(JBossMessage message, boolean checkForDuplicates) throws JMSException
    {
    	throw new IllegalStateException("Should not be handled on the server");
    }
-   
-   public void send(JBossMessage message, boolean checkForDuplicates, long thisSequence) throws JMSException
+     
+   public void send(JBossMessage message, final boolean checkForDuplicates, long thisSequence) throws JMSException
    {
       try
       {                
       	if (thisSequence != -1)
       	{
-      		//Need to make sure it is in correct order since np messages are sent
-      		//one way so they can arrive out of sequence
-      		
-      		//This is a workaround to allow us to use one way messages for np messages for performance
-      		//reasons
-      		
-      		synchronized (waitLock)
-      		{	      		      	        
-	      		if (thisSequence == expectedSequence)
-	      		{
-	      			do
-	      			{
-	      				connectionEndpoint.sendMessage(message, null, checkForDuplicates); 
-	      				
-	         			expectedSequence++;
-	         			
-	         			message = (JBossMessage)heldBack.remove(expectedSequence);
-	      				
-	      			} while (message != null);	      			
-	      		}
-	      		else
-	      		{
-	      			//Not the expected one - add it to the map
-	      			
-	      			heldBack.put(thisSequence, message);      			
-	      		}
-	      		
-	      		waitLock.notify();
-      		}
+      	   reorderer.handle(message, thisSequence);
       	}
       	else
       	{
@@ -645,7 +589,7 @@
          	}
          }
          
-         this.deliveryIdSequence = new SynchronizedLong(maxDeliveryId + 1);
+         deliveryIdSequence = maxDeliveryId + 1;
       }
       catch (Throwable t)
       {
@@ -1331,7 +1275,7 @@
    	 
    	 DeliveryRecord rec = null;
    	 
-   	 deliveryId = deliveryIdSequence.increment();   	 
+   	 deliveryId = deliveryIdSequence++;
    	 
    	 if (trace) { log.trace("Delivery id is now " + deliveryId); }
    	 
@@ -1459,39 +1403,17 @@
 
       try
       {
-         // FIXME - due a design (flaw??) in the socket based transports, they use a pool of TCP
-         // connections, so subsequent invocations can end up using different underlying
-         // connections meaning that later invocations can overtake earlier invocations, if there
-         // are more than one user concurrently invoking on the same transport. We need someway
-         // of pinning the client object to the underlying invocation. For now we just serialize
-         // all access so that only the first connection in the pool is ever used - but this is
-         // far from ideal!!!
-         // See http://jira.jboss.com/jira/browse/JBMESSAGING-789
-
-         Object invoker = null;
-
-         if (callbackClient != null)
-         {
-            invoker = callbackClient.getInvoker();                              
-         }
-         else
-         {
-            // TODO: dummy synchronization object, in case there's no clientInvoker. This will
-            // happen during the first invocation anyway. It's a kludge, I know, but this whole
-            // synchronization thing is a huge kludge. Needs to be reviewed.
-            invoker = new Object();
-         }
+         //Note - even though remoting cannot guarantee ordering of one way invocations unless client pool size =1
+         //in which case performance would be crippled - so this is not an option.
+         //We use a reorderer on the client side to re-order deliveries that may have got out of order
          
-         synchronized (invoker)
-         {
-            // one way invocation, no acknowledgment sent back by the client
-            if (trace) { log.trace(this + " submitting message " + ref.getMessage() + " to the remoting layer to be sent asynchronously"); }
-            
-            callbackHandler.handleCallbackOneway(callback);
-                                    
-            //We store the delivery id so we know to wait for any deliveries in transit on close
-            consumer.setLastDeliveryID(deliveryID);
-         }
+         // one way invocation, no acknowledgment sent back by the client
+         if (trace) { log.trace(this + " submitting message " + ref.getMessage() + " to the remoting layer to be sent asynchronously"); }
+         
+         callbackHandler.handleCallbackOneway(callback);
+                                 
+         //We store the delivery id so we know to wait for any deliveries in transit on close
+         consumer.setLastDeliveryID(deliveryID);        
       }
       catch (Throwable t)
       {
@@ -2412,4 +2334,12 @@
          delList.add(deliveryId);
       }
    }
+   
+   private class SendReorderer extends Reorderer
+   {
+      public void execute(Object object) throws Exception
+      {
+         connectionEndpoint.sendMessage((JBossMessage)object, null, false);
+      }
+   }
 }

Added: branches/Branch_Stable/src/main/org/jboss/messaging/util/Reorderer.java
===================================================================
--- branches/Branch_Stable/src/main/org/jboss/messaging/util/Reorderer.java	                        (rev 0)
+++ branches/Branch_Stable/src/main/org/jboss/messaging/util/Reorderer.java	2007-11-27 19:43:01 UTC (rev 3371)
@@ -0,0 +1,107 @@
+/*
+  * 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.messaging.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.logging.Logger;
+
+/**
+ * 
+ * A Reorderer
+ * 
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public abstract class Reorderer
+{
+   private static final Logger log = Logger.getLogger(Reorderer.class);   
+   
+   private static final long WAIT_TIMEOUT = 5 * 1000;
+      
+   private long expectedSequence = 0;
+   
+   private Map<Long, Object> heldBack = new HashMap<Long, Object>();
+   
+   public synchronized void reset()
+   {
+      heldBack.clear();
+      
+      expectedSequence = 0;
+   }
+   
+   public synchronized void handle(Object object, long thisSequence) throws Exception
+   {
+      //Need to make sure it is in correct order since np messages are sent
+      //one way so they can arrive out of sequence
+      
+      //This is a workaround to allow us to use one way messages for np messages for performance
+      //reasons
+                           
+      if (thisSequence == expectedSequence)
+      {
+         do
+         {
+            execute(object);
+            
+            expectedSequence++;
+            
+            object = heldBack.remove(expectedSequence);
+            
+         } while (object != null);                
+      }
+      else
+      {
+         //Not the expected one - add it to the map
+         
+         heldBack.put(thisSequence, object);               
+      }
+      
+      notify();      
+   }
+   
+   public synchronized void waitToArrive(long sequence)
+   {          
+      long wait = WAIT_TIMEOUT;
+      
+      while (sequence != expectedSequence && wait > 0)
+      {
+         long start = System.currentTimeMillis(); 
+         try
+         {
+            wait();
+         }
+         catch (InterruptedException e)
+         {                 
+         }
+         wait -= (System.currentTimeMillis() - start);
+      }
+      
+      if (wait <= 0)
+      {
+         log.warn("Timed out waiting for last message");
+      }             
+   }
+   
+   public abstract void execute(Object object) throws Exception;   
+}

Added: branches/Branch_Stable/tests/src/org/jboss/test/messaging/util/ReordererTest.java
===================================================================
--- branches/Branch_Stable/tests/src/org/jboss/test/messaging/util/ReordererTest.java	                        (rev 0)
+++ branches/Branch_Stable/tests/src/org/jboss/test/messaging/util/ReordererTest.java	2007-11-27 19:43:01 UTC (rev 3371)
@@ -0,0 +1,188 @@
+/**
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.test.messaging.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.messaging.util.Reorderer;
+import org.jboss.test.messaging.MessagingTestCase;
+
+/**
+ * 
+ * A ReordererTest
+ * 
+ * @author <a href="mailto:tim.fox at jboss.com">Tim Fox</a>
+ *
+ */
+public class ReordererTest extends MessagingTestCase
+{
+   // Constants ------------------------------------------------------------------------------------
+
+   // Static ---------------------------------------------------------------------------------------
+
+   // Attributes -----------------------------------------------------------------------------------
+
+   // Constructors ---------------------------------------------------------------------------------
+
+   public ReordererTest(String name)
+   {
+      super(name);
+   }
+
+   // Public ---------------------------------------------------------------------------------------  
+
+   public void testOrder() throws Exception
+   {
+      final List<Integer> list = new ArrayList<Integer>();
+      
+      class MyReorderer extends Reorderer
+      {
+         @Override
+         public void execute(Object object) throws Exception
+         {
+            list.add((Integer)object);
+         }         
+      }
+      
+      Reorderer reorderer = new MyReorderer();
+      
+      reorderer.handle(3, 3);
+      reorderer.handle(1, 1);
+      reorderer.handle(9, 9);
+      reorderer.handle(6, 6);
+      reorderer.handle(0, 0);
+      reorderer.handle(2, 2);
+      reorderer.handle(5, 5);
+      reorderer.handle(8, 8);
+      reorderer.handle(7, 7);
+      reorderer.handle(4, 4);
+   
+      for (int i = 0; i < 10; i++)
+      {
+         assertEquals(Integer.valueOf(i), (Integer)list.get(i));
+      }
+   
+   }
+   
+   public void testHoldBack() throws Exception
+   {
+      final List<Integer> list = new ArrayList<Integer>();
+      
+      class MyReorderer extends Reorderer
+      {
+         @Override
+         public void execute(Object object) throws Exception
+         {
+            list.add((Integer)object);
+         }         
+      }
+      
+      Reorderer reorderer = new MyReorderer();
+      
+      reorderer.handle(3, 3);
+      assertTrue(list.isEmpty());
+      reorderer.handle(1, 1);
+      assertTrue(list.isEmpty());
+      reorderer.handle(9, 9);
+      assertTrue(list.isEmpty());
+      reorderer.handle(6, 6);
+      assertTrue(list.isEmpty());
+      reorderer.handle(0, 0);
+      assertEquals(Integer.valueOf(0), (Integer)list.get(0));
+      assertEquals(Integer.valueOf(1), (Integer)list.get(1));
+      assertEquals(2, list.size());
+      reorderer.handle(2, 2);
+      assertEquals(Integer.valueOf(0), (Integer)list.get(0));
+      assertEquals(Integer.valueOf(1), (Integer)list.get(1));
+      assertEquals(Integer.valueOf(2), (Integer)list.get(2));
+      assertEquals(Integer.valueOf(3), (Integer)list.get(3));
+      assertEquals(4, list.size());
+      reorderer.handle(5, 5);
+      assertEquals(Integer.valueOf(0), (Integer)list.get(0));
+      assertEquals(Integer.valueOf(1), (Integer)list.get(1));
+      assertEquals(Integer.valueOf(2), (Integer)list.get(2));
+      assertEquals(Integer.valueOf(3), (Integer)list.get(3));
+      assertEquals(4, list.size());
+      reorderer.handle(4, 4);
+      assertEquals(Integer.valueOf(0), (Integer)list.get(0));
+      assertEquals(Integer.valueOf(1), (Integer)list.get(1));
+      assertEquals(Integer.valueOf(2), (Integer)list.get(2));
+      assertEquals(Integer.valueOf(3), (Integer)list.get(3));
+      assertEquals(Integer.valueOf(4), (Integer)list.get(4));
+      assertEquals(Integer.valueOf(5), (Integer)list.get(5));
+      assertEquals(Integer.valueOf(6), (Integer)list.get(6));
+      assertEquals(7, list.size());
+      reorderer.handle(8, 8);
+      assertEquals(Integer.valueOf(0), (Integer)list.get(0));
+      assertEquals(Integer.valueOf(1), (Integer)list.get(1));
+      assertEquals(Integer.valueOf(2), (Integer)list.get(2));
+      assertEquals(Integer.valueOf(3), (Integer)list.get(3));
+      assertEquals(Integer.valueOf(4), (Integer)list.get(4));
+      assertEquals(Integer.valueOf(5), (Integer)list.get(5));
+      assertEquals(Integer.valueOf(6), (Integer)list.get(6));
+      assertEquals(7, list.size());
+      reorderer.handle(7, 7);
+      assertEquals(Integer.valueOf(0), (Integer)list.get(0));
+      assertEquals(Integer.valueOf(1), (Integer)list.get(1));
+      assertEquals(Integer.valueOf(2), (Integer)list.get(2));
+      assertEquals(Integer.valueOf(3), (Integer)list.get(3));
+      assertEquals(Integer.valueOf(4), (Integer)list.get(4));
+      assertEquals(Integer.valueOf(5), (Integer)list.get(5));
+      assertEquals(Integer.valueOf(6), (Integer)list.get(6));
+      assertEquals(Integer.valueOf(7), (Integer)list.get(7));
+      assertEquals(Integer.valueOf(8), (Integer)list.get(8));
+      assertEquals(Integer.valueOf(9), (Integer)list.get(9));
+      assertEquals(10, list.size());
+      
+   
+      for (int i = 0; i < 10; i++)
+      {
+         assertEquals(Integer.valueOf(i), (Integer)list.get(i));
+      }
+   
+   }
+   
+   public void testOrderMustStartWithZero() throws Exception
+   {
+      final List<Integer> list = new ArrayList<Integer>();
+      
+      class MyReorderer extends Reorderer
+      {
+         @Override
+         public void execute(Object object) throws Exception
+         {
+            list.add((Integer)object);
+         }         
+      }
+      
+      Reorderer reorderer = new MyReorderer();
+      
+      reorderer.handle(3, 3);
+      reorderer.handle(1, 1);
+      reorderer.handle(9, 9);
+      reorderer.handle(6, 6);
+      reorderer.handle(2, 2);
+      reorderer.handle(5, 5);
+      reorderer.handle(8, 8);
+      reorderer.handle(7, 7);
+      reorderer.handle(4, 4);
+   
+      assertTrue(list.isEmpty());
+   
+   }
+   
+   // Package protected ----------------------------------------------------------------------------
+
+   // Protected ------------------------------------------------------------------------------------
+
+   // Private --------------------------------------------------------------------------------------
+
+   // Inner classes --------------------------------------------------------------------------------
+   
+   
+}




More information about the jboss-cvs-commits mailing list