Package org.jboss.test.messaging.core

Source Code of org.jboss.test.messaging.core.SimpleReceiver$PostAcknowledgeCommitCallback

/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.messaging.core;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

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.Receiver;
import org.jboss.messaging.core.SimpleDelivery;
import org.jboss.messaging.core.message.Message;
import org.jboss.messaging.core.message.MessageReference;
import org.jboss.messaging.core.tx.Transaction;
import org.jboss.messaging.core.tx.TxCallback;
import org.jboss.util.id.GUID;

/**
* A simple Receiver implementation that consumes undelivered by storing them internally. Used for
* testing. The receiver can be configured to immediately return a "done" delivery (ACKING),
* an "active" delivery (NACKING) undelivered, or throw unchecked exceptions.
*
* @author <a href="mailto:ovidiu@jboss.org">Ovidiu Feodorov</a>
* @author <a href="mailto:tim.fox@jboss.com">Tim Fox</a>
* @version <tt>$Revision: 2491 $</tt>
*
* $Id: SimpleReceiver.java 2491 2007-02-28 06:54:10Z ovidiu.feodorov@jboss.com $
*/
public class SimpleReceiver implements Receiver
{
   // Constants -----------------------------------------------------

   private static final Logger log = Logger.getLogger(SimpleReceiver.class);

   public static final String ACKING = "ACKING";
   public static final String ACCEPTING = "ACCEPTING";
   public static final String BROKEN = "BROKEN";
   public static final String REJECTING = "REJECTING";
   public static final String SELECTOR_REJECTING = "SELECTOR_REJECTING";
   public static final String ACCEPTING_TO_MAX = "ACCEPTING_TO_MAX";

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

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

   // <Object[2] { Routable, Delivery }>
   private List messages;
   private String state;
   private String name;
   private Channel channel;
  
   private boolean immediateAsynchronousAcknowledgment;
   private int maxRefs;
  
   private int count;
   private int waitForCount = -1;
  

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

   public SimpleReceiver()
   {
      this(ACKING);
   }

   public SimpleReceiver(String name)
   {
      this(name, ACKING);
   }

   /**
    *
    * @param name
    * @param state:
    *        ACKING - the receiver returns synchronously a "done" delivery.
    *        NACKING - the receiver returns an active delivery, and has the option of acking it later
    *        BROKEN - throws exception
    */
   public SimpleReceiver(String name, String state)
   {
      this(name, state, null);
   }
  

   public SimpleReceiver(String name, String state, Channel channel)
   {
      checkValid(state);

      this.name = name;
      this.state = state;
      this.channel = channel;
      messages = new ArrayList();
      immediateAsynchronousAcknowledgment = false;
   }

   // Receiver implementation ---------------------------------------

   public Delivery handle(DeliveryObserver observer, MessageReference ref, Transaction tx)
   {
      log.trace(this + " got routable:" + ref);
         
      try
      {
         if (ref == null)
         {
            log.trace("Receiver [" + name + "] is rejecting a null reference");
            return null;
         }
        
         if (SELECTOR_REJECTING.equals(state))
         {
            log.trace(this + " is rejecting message since doesn't match selector");
            return new SimpleDelivery(null, null, true, false);
         }

         if (REJECTING.equals(state))
         {

            log.trace(this + " is rejecting reference " + ref);
            return null;
         }
        
         if (ACCEPTING_TO_MAX.equals(state))
         {
            //Only accept up to maxRefs references
            if (messages.size() == maxRefs)
            {
               return null;
            }
         }

         if (BROKEN.equals(state))
         {
            throw new RuntimeException("THIS IS AN EXCEPTION THAT SIMULATES "+
                                       "THE BEHAVIOUR OF A BROKEN RECEIVER");
         }

         log.trace("State is:" + state);
        
         boolean done = ACKING.equals(state);
        
         //NOTE! it is NOT Nacking, it is keeping - don't say NACKing - it is misleading (nack means cancel)        
         log.trace(this + " is " + (done ? "ACKing" : "Keeping") " message " + ref);
        
         Message m = ref.getMessage();
        
         SimpleDelivery delivery = new SimpleDelivery(observer, ref, done);
         messages.add(new Object[] {m, done ? null : delivery});
        
         if (immediateAsynchronousAcknowledgment)
         {
            log.trace("simulating an asynchronous ACK that arrives before we return the delivery to channel");
            try
            {
               delivery.acknowledge(null);
            }
            catch(Throwable t)
            {
               log.error("Cannot acknowledge", t);
            }
         }
         return delivery;
      }
      finally
      {
         synchronized (this)
         {
            count++;
            if (waitForCount != -1 && count >= waitForCount)
            {
               this.notify();
            }
         }        
      }
   }
  
   // Public --------------------------------------------------------
  
   public void setMaxRefs(int max)
   {
      this.maxRefs = max;
   }

   public void setImmediateAsynchronousAcknowledgment(boolean b)
   {
      immediateAsynchronousAcknowledgment = b;
   }

   public String getName()
   {
      return name;
   }

   public void requestMessages()
   {
      if (channel == null)
      {
         log.error("No channel, cannot request messages");
         return;
      }
      log.trace("receiver explicitely requesting message from the channel");
      channel.deliver();
   }

   public void clear()
   {
      messages.clear();
   }

   public List getMessages()
   {
      List l = new ArrayList();
      for (Iterator i = messages.iterator(); i.hasNext(); )
      {
         Object[] o = (Object[])i.next();
         l.add(o[0]);
      }
      return l;
   }

   /**
    * Blocks until handle() is called for the specified number of times.
    *
    * @return true if the handle was invoked the specified number of times or false if the method
    *         exited with timeout.
    */
   public boolean waitForHandleInvocations(int waitFor, long timeout)
   {
      long start = System.currentTimeMillis();
     
      synchronized(this)
      {
         this.waitForCount = waitFor;
        
         while (this.count < waitForCount)
         {     
            if (timeout < 0)
            {
               log.trace(this + ".waitForHandleInvocations() current timeout is " + timeout);
               resetInvocationCount();
               return false;
            }
           
            try
            {
               this.wait(timeout);
               long now = System.currentTimeMillis();
               timeout -= now - start;
               start = now;
            }
            catch(InterruptedException e)
            {
               log.debug(e);
            }
         }
      }
     
      resetInvocationCount();
      return true;
   }

   public void acknowledge(Message r, Transaction tx) throws Throwable
   {
      log.debug(this + " acknowledging "  + r);

      Object[] touple = null;
      Delivery d = null;
      for (Iterator i = messages.iterator(); i.hasNext(); )
      {
         Object[] o = (Object[])i.next();
         Message m = (Message)o[0];
         if (m == r)
         {
            log.trace("*** found it");
            d = (Delivery)o[1];
            touple = o;
            break;
         }
      }

      if (touple == null)
      {
         throw new IllegalStateException("The message " + r + " hasn't been received yet!");
      }

      if (d == null)
      {
         throw new IllegalStateException("The message " + r + " has already been acknowledged!");
      }

      d.acknowledge(tx);

      log.trace(this + " acknowledged "  + r);

      // make sure I get rid of message if the transaction is rolled back
      if (tx != null)
      {
         tx.addCallback(new PostAcknowledgeCommitCallback(touple), new GUID().toString());
      }
   }

   public void cancel(Message r) throws Throwable
   {
      Object[] touple = null;
      Delivery d = null;
      for (Iterator i = messages.iterator(); i.hasNext(); )
      {
         Object[] o = (Object[])i.next();
         Message m = (Message)o[0];
         if (m == r)
         {
            d = (Delivery)o[1];
            touple = o;
            i.remove();
            break;
         }
      }

      if (touple == null)
      {
         throw new IllegalStateException("The message " + r + " hasn't been received yet!");
      }

      if (d == null)
      {
         throw new IllegalStateException("The message " + r + " has already been acknowledged!");
      }

      d.cancel();

      log.trace(this + " cancelled "  + r);
   }

   public String toString()
   {
      return "Receiver["+ name +"](" + state + ")";
   }

   // Package protected ---------------------------------------------
  
   // Protected -----------------------------------------------------
  
   // Private -------------------------------------------------------

   private static void checkValid(String state)
   {
      if (!ACKING.equals(state) &&
          !ACCEPTING.equals(state) &&
          !BROKEN.equals(state) &&
          !REJECTING.equals(state) &&
          !SELECTOR_REJECTING.equals(state) &&
          !ACCEPTING_TO_MAX.equals(state))
      {
         throw new IllegalArgumentException("Unknown receiver state: " + state);
      }
   }
  
   private void resetInvocationCount()
   {
     this.waitForCount = -1;
     this.count = 0;     
   }

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

   private class PostAcknowledgeCommitCallback implements TxCallback
   {
      private Object[] touple;


      /**
       * @param touple - touple[0] contains the message, touple[1] contains the delivery
       */
      public PostAcknowledgeCommitCallback(Object[] touple)
      {
         this.touple = touple;
      }

      public void afterRollback(boolean onePhase)
      {
        
      }
     
      public void afterCommit()
      {
         // clear the delivery
         touple[1] = null;
      }

      public void afterCommit(boolean onePhase) throws Exception
      {
        
      }

      public void afterPrepare() throws Exception
      {
        
      }

      public void beforeCommit(boolean onePhase) throws Exception
      {
      }

      public void beforePrepare() throws Exception
      {
  
      }

      public void beforeRollback(boolean onePhase) throws Exception
      {

      }
   }
}
TOP

Related Classes of org.jboss.test.messaging.core.SimpleReceiver$PostAcknowledgeCommitCallback

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