Coverage Report - org.mule.providers.vm.VMMessageReceiver
 
Classes in this File Line Coverage Branch Coverage Complexity
VMMessageReceiver
95%
39/41
79%
11/14
1.583
VMMessageReceiver$VMReceiverWorker
100%
5/5
100%
2/2
1.583
 
 1  
 /*
 2  
  * $Id: VMMessageReceiver.java 10063 2007-12-11 11:57:03Z holger $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.providers.vm;
 12  
 
 13  
 import org.mule.impl.MuleMessage;
 14  
 import org.mule.providers.PollingReceiverWorker;
 15  
 import org.mule.providers.TransactedPollingMessageReceiver;
 16  
 import org.mule.umo.UMOComponent;
 17  
 import org.mule.umo.UMOEvent;
 18  
 import org.mule.umo.UMOException;
 19  
 import org.mule.umo.UMOMessage;
 20  
 import org.mule.umo.endpoint.UMOEndpoint;
 21  
 import org.mule.umo.lifecycle.InitialisationException;
 22  
 import org.mule.umo.provider.UMOConnector;
 23  
 import org.mule.util.queue.Queue;
 24  
 import org.mule.util.queue.QueueSession;
 25  
 
 26  
 import java.util.LinkedList;
 27  
 import java.util.List;
 28  
 
 29  
 import edu.emory.mathcs.backport.java.util.concurrent.RejectedExecutionException;
 30  
 
 31  
 /**
 32  
  * <code>VMMessageReceiver</code> is a listener for events from a Mule component which
 33  
  * then simply passes the events on to the target component.
 34  
  */
 35  
 public class VMMessageReceiver extends TransactedPollingMessageReceiver
 36  
 {
 37  
 
 38  
     private VMConnector connector;
 39  44
     private final Object lock = new Object();
 40  
 
 41  
     public VMMessageReceiver(UMOConnector connector, UMOComponent component, UMOEndpoint endpoint)
 42  
         throws InitialisationException
 43  
     {
 44  44
         super(connector, component, endpoint);
 45  44
         this.setReceiveMessagesInTransaction(endpoint.getTransactionConfig().isTransacted());
 46  44
         this.connector = (VMConnector) connector;
 47  44
     }
 48  
 
 49  
     /*
 50  
      * We only need to start scheduling this receiver if event queueing is enabled on the
 51  
      * connector; otherwise events are delivered via onEvent/onCall.
 52  
      */
 53  
     // @Override
 54  
     protected void schedule()
 55  
         throws RejectedExecutionException, NullPointerException, IllegalArgumentException
 56  
     {
 57  40
         if (connector.isQueueEvents())
 58  
         {
 59  24
             super.schedule();
 60  
         }
 61  40
     }
 62  
 
 63  
     protected void doDispose()
 64  
     {
 65  
         // template method
 66  44
     }
 67  
 
 68  
     protected void doConnect() throws Exception
 69  
     {
 70  40
         if (connector.isQueueEvents())
 71  
         {
 72  
             // Ensure we can create a vm queue
 73  24
             QueueSession queueSession = connector.getQueueSession();
 74  24
             Queue q = queueSession.getQueue(endpoint.getEndpointURI().getAddress());
 75  24
             if (logger.isDebugEnabled())
 76  
             {
 77  0
                 logger.debug("Current queue depth for queue: " + endpoint.getEndpointURI().getAddress()
 78  
                              + " is: " + q.size());
 79  
             }
 80  
         }
 81  40
     }
 82  
 
 83  
     protected void doDisconnect() throws Exception
 84  
     {
 85  
         // template method
 86  40
     }
 87  
 
 88  
     public void onEvent(UMOEvent event) throws UMOException
 89  
     {
 90  
         /*
 91  
          * TODO HH: review: onEvent can only be called by the VMMessageDispatcher - why is
 92  
          * this lock here and do we still need it? what can break if this receiver is run
 93  
          * concurrently by multiple dispatchers?
 94  
          */
 95  10
         UMOMessage msg = new MuleMessage(event.getTransformedMessage(), event.getMessage());
 96  10
         synchronized (lock)
 97  
         {
 98  10
             routeMessage(msg);
 99  10
         }
 100  10
     }
 101  
 
 102  
     public Object onCall(UMOEvent event) throws UMOException
 103  
     {
 104  4
         UMOMessage msg = new MuleMessage(event.getTransformedMessage(), event.getMessage());
 105  4
         return routeMessage(msg, event.isSynchronous());
 106  
     }
 107  
 
 108  
     protected List getMessages() throws Exception
 109  
     {
 110  
         // The queue from which to pull events
 111  44
         QueueSession qs = connector.getQueueSession();
 112  44
         Queue queue = qs.getQueue(endpoint.getEndpointURI().getAddress());
 113  
 
 114  
         // The list of retrieved messages that will be returned
 115  44
         List messages = new LinkedList();
 116  
 
 117  
         /*
 118  
          * Determine how many messages to batch in this poll: we need to drain the queue
 119  
          * quickly, but not by slamming the workManager too hard. It is impossible to
 120  
          * determine this more precisely without proper load statistics/feedback or some
 121  
          * kind of "event cost estimate". Therefore we just try to use half of the
 122  
          * receiver's workManager, since it is shared with receivers for other endpoints.
 123  
          */
 124  44
         int maxThreads = connector.getReceiverThreadingProfile().getMaxThreadsActive();
 125  
         // also make sure batchSize is always at least 1
 126  44
         int batchSize = Math.max(1, Math.min(queue.size(), ((maxThreads / 2) - 1)));
 127  
 
 128  
         // try to get the first event off the queue
 129  44
         UMOEvent event = (UMOEvent) queue.poll(connector.getQueueTimeout());
 130  
 
 131  32
         if (event != null)
 132  
         {
 133  
             // keep first dequeued event
 134  12
             messages.add(event);
 135  
 
 136  
             // keep batching if more events are available
 137  24
             for (int i = 0; i < batchSize && event != null; i++)
 138  
             {
 139  12
                 event = (UMOEvent) queue.poll(0);
 140  12
                 if (event != null)
 141  
                 {
 142  0
                     messages.add(event);
 143  
                 }
 144  
             }
 145  
         }
 146  
 
 147  
         // let our workManager handle the batch of events
 148  32
         return messages;
 149  
     }
 150  
 
 151  
     protected void processMessage(Object msg) throws Exception
 152  
     {
 153  
         // getMessages() returns UMOEvents
 154  12
         UMOEvent event = (UMOEvent) msg;
 155  12
         UMOMessage message = new MuleMessage(event.getTransformedMessage(), event.getMessage());
 156  12
         routeMessage(message);
 157  12
     }
 158  
 
 159  
     /*
 160  
      * We create our own "polling" worker here since we need to evade the standard scheduler.
 161  
      */
 162  
     // @Override
 163  
     protected PollingReceiverWorker createWork()
 164  
     {
 165  24
         return new VMReceiverWorker(this);
 166  
     }
 167  
 
 168  
     /*
 169  
      * Even though the VM transport is "polling" for messages, the nonexistent cost of
 170  
      * accessing the queue is a good reason to not use the regular scheduling mechanism in
 171  
      * order to both minimize latency and maximize throughput.
 172  
      */
 173  
     protected static class VMReceiverWorker extends PollingReceiverWorker
 174  
     {
 175  
 
 176  
         public VMReceiverWorker(VMMessageReceiver pollingMessageReceiver)
 177  
         {
 178  24
             super(pollingMessageReceiver);
 179  24
         }
 180  
 
 181  
         public void run()
 182  
         {
 183  
             /*
 184  
              * We simply run our own polling loop all the time as long as the receiver is
 185  
              * started. The blocking wait defined by VMConnector.getQueueTimeout() will
 186  
              * prevent this worker's receiver thread from busy-waiting.
 187  
              */
 188  60
             while (this.getReceiver().isConnected())
 189  
             {
 190  44
                 super.run();
 191  
             }
 192  16
         }
 193  
     }
 194  
 
 195  
 }