Coverage Report - org.mule.transport.vm.VMMessageReceiver
 
Classes in this File Line Coverage Branch Coverage Complexity
VMMessageReceiver
0%
0/55
0%
0/22
0
VMMessageReceiver$VMReceiverWorker
0%
0/5
0%
0/2
0
 
 1  
 /*
 2  
  * $Id: VMMessageReceiver.java 20351 2010-11-25 18:01:47Z svacas $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.transport.vm;
 12  
 
 13  
 import org.mule.DefaultMuleMessage;
 14  
 import org.mule.api.DefaultMuleException;
 15  
 import org.mule.api.MuleEvent;
 16  
 import org.mule.api.MuleException;
 17  
 import org.mule.api.MuleMessage;
 18  
 import org.mule.api.construct.FlowConstruct;
 19  
 import org.mule.api.endpoint.InboundEndpoint;
 20  
 import org.mule.api.lifecycle.CreateException;
 21  
 import org.mule.api.transport.Connector;
 22  
 import org.mule.transport.PollingReceiverWorker;
 23  
 import org.mule.transport.TransactedPollingMessageReceiver;
 24  
 import org.mule.util.queue.Queue;
 25  
 import org.mule.util.queue.QueueSession;
 26  
 
 27  
 import java.util.ArrayList;
 28  
 import java.util.LinkedList;
 29  
 import java.util.List;
 30  
 
 31  
 import edu.emory.mathcs.backport.java.util.concurrent.RejectedExecutionException;
 32  
 
 33  
 /**
 34  
  * <code>VMMessageReceiver</code> is a listener for events from a Mule service which then simply passes
 35  
  * the events on to the target service.
 36  
  */
 37  
 public class VMMessageReceiver extends TransactedPollingMessageReceiver
 38  
 {
 39  
 
 40  
     private VMConnector connector;
 41  
 
 42  
     public VMMessageReceiver(Connector connector, FlowConstruct flowConstruct, InboundEndpoint endpoint)
 43  
         throws CreateException
 44  
     {
 45  0
         super(connector, flowConstruct, endpoint);
 46  0
         this.setReceiveMessagesInTransaction(endpoint.getTransactionConfig().isTransacted());
 47  0
         this.connector = (VMConnector) connector;
 48  0
     }
 49  
 
 50  
     /*
 51  
      * We only need to start scheduling this receiver if event queueing is enabled on the connector; otherwise
 52  
      * events are delivered via onEvent/onCall.
 53  
      */
 54  
     @Override
 55  
     protected void schedule() throws RejectedExecutionException, NullPointerException, IllegalArgumentException
 56  
     {
 57  0
         if (!endpoint.getExchangePattern().hasResponse())
 58  
         {
 59  0
             super.schedule();
 60  
         }
 61  0
     }
 62  
 
 63  
     @Override
 64  
     protected void doDispose()
 65  
     {
 66  
         // template method
 67  0
     }
 68  
 
 69  
     @Override
 70  
     protected void doConnect() throws Exception
 71  
     {
 72  0
         if (!endpoint.getExchangePattern().hasResponse())
 73  
         {
 74  
             // Ensure we can create a vm queue
 75  0
             QueueSession queueSession = connector.getQueueSession();
 76  0
             Queue q = queueSession.getQueue(endpoint.getEndpointURI().getAddress());
 77  0
             if (logger.isDebugEnabled())
 78  
             {
 79  0
                 logger.debug("Current queue depth for queue: " + endpoint.getEndpointURI().getAddress() + " is: "
 80  
                              + q.size());
 81  
             }
 82  
         }
 83  0
     }
 84  
 
 85  
     @Override
 86  
     protected void doDisconnect() throws Exception
 87  
     {
 88  
         // template method
 89  0
     }
 90  
 
 91  
     public void onMessage(MuleMessage message) throws MuleException
 92  
     {
 93  
         // Rewrite the message to treat it as a new message
 94  0
         MuleMessage newMessage = new DefaultMuleMessage(message.getPayload(), message, connector.getMuleContext());
 95  0
         routeMessage(newMessage);
 96  0
     }
 97  
 
 98  
     public MuleMessage onCall(MuleMessage message) throws MuleException
 99  
     {
 100  
         try
 101  
         {
 102  
             // Rewrite the message to treat it as a new message
 103  0
             MuleMessage newMessage = message.createInboundMessage();
 104  0
             MuleEvent event =  routeMessage(newMessage);
 105  0
             MuleMessage returnedMessage = event == null ? null : event.getMessage();
 106  0
             if (returnedMessage != null)
 107  
             {
 108  0
                 returnedMessage = returnedMessage.createInboundMessage();
 109  
             }
 110  0
             return returnedMessage;
 111  
         }
 112  0
         catch (Exception e)
 113  
         {
 114  0
             throw new DefaultMuleException(e);
 115  
         }
 116  
     }
 117  
 
 118  
     /**
 119  
      * It's impossible to process all messages in the receive transaction
 120  
      */
 121  
     @Override
 122  
     protected List<MuleMessage> getMessages() throws Exception
 123  
     {
 124  0
         if (isReceiveMessagesInTransaction())
 125  
         {
 126  0
             MuleEvent message = getFirstMessage();
 127  0
             if (message == null)
 128  
             {
 129  0
                 return null;
 130  
             }
 131  
             
 132  0
             List<MuleMessage> messages = new ArrayList<MuleMessage>(1);
 133  0
             messages.add(message.getMessage());
 134  0
             return messages;
 135  
         }
 136  
         else
 137  
         {
 138  0
             return getFirstMessages();
 139  
         }
 140  
     }
 141  
     
 142  
     protected List<MuleMessage> getFirstMessages() throws Exception
 143  
     {
 144  
         // The queue from which to pull events
 145  0
         QueueSession qs = connector.getQueueSession();
 146  0
         Queue queue = qs.getQueue(endpoint.getEndpointURI().getAddress());
 147  
 
 148  
         // The list of retrieved messages that will be returned
 149  0
         List<MuleMessage> messages = new LinkedList<MuleMessage>();
 150  
 
 151  
         /*
 152  
          * Determine how many messages to batch in this poll: we need to drain the queue quickly, but not by
 153  
          * slamming the workManager too hard. It is impossible to determine this more precisely without proper
 154  
          * load statistics/feedback or some kind of "event cost estimate". Therefore we just try to use half
 155  
          * of the receiver's workManager, since it is shared with receivers for other endpoints.
 156  
          */
 157  0
         int maxThreads = connector.getReceiverThreadingProfile().getMaxThreadsActive();
 158  
         // also make sure batchSize is always at least 1
 159  0
         int batchSize = Math.max(1, Math.min(queue.size(), ((maxThreads / 2) - 1)));
 160  
 
 161  
         // try to get the first event off the queue
 162  0
         MuleEvent message = (MuleEvent) queue.poll(connector.getQueueTimeout());
 163  
 
 164  0
         if (message != null)
 165  
         {
 166  
             // keep first dequeued event
 167  0
             messages.add(message.getMessage());
 168  
 
 169  
             // keep batching if more events are available
 170  0
             for (int i = 0; i < batchSize && message != null; i++)
 171  
             {
 172  0
                 message = (MuleEvent)queue.poll(0);
 173  0
                 if (message != null)
 174  
                 {
 175  0
                     messages.add(message.getMessage());
 176  
                 }
 177  
             }
 178  
         }
 179  
 
 180  
         // let our workManager handle the batch of events
 181  0
         return messages;
 182  
     }
 183  
     
 184  
     protected MuleEvent getFirstMessage() throws Exception
 185  
     {
 186  
         // The queue from which to pull events
 187  0
         QueueSession qs = connector.getQueueSession();
 188  0
         Queue queue = qs.getQueue(endpoint.getEndpointURI().getAddress());
 189  
         // try to get the first event off the queue
 190  0
         return (MuleEvent) queue.poll(connector.getQueueTimeout());
 191  
     }
 192  
 
 193  
     @Override
 194  
     protected void processMessage(Object msg) throws Exception
 195  
     {
 196  0
         MuleMessage message = (MuleMessage) msg;
 197  
 
 198  
         // Rewrite the message to treat it as a new message
 199  0
         MuleMessage newMessage = message.createInboundMessage();
 200  0
         routeMessage(newMessage);
 201  0
     }
 202  
 
 203  
     /*
 204  
      * We create our own "polling" worker here since we need to evade the standard scheduler.
 205  
      */
 206  
     @Override
 207  
     protected PollingReceiverWorker createWork()
 208  
     {
 209  0
         return new VMReceiverWorker(this);
 210  
     }
 211  
     
 212  
     /*
 213  
      * Even though the VM transport is "polling" for messages, the nonexistent cost of accessing the queue is
 214  
      * a good reason to not use the regular scheduling mechanism in order to both minimize latency and
 215  
      * maximize throughput.
 216  
      */
 217  
     protected static class VMReceiverWorker extends PollingReceiverWorker
 218  
     {
 219  
 
 220  
         public VMReceiverWorker(VMMessageReceiver pollingMessageReceiver)
 221  
         {
 222  0
             super(pollingMessageReceiver);
 223  0
         }
 224  
 
 225  
         @Override
 226  
         protected void poll() throws Exception
 227  
         {
 228  
             /*
 229  
              * We simply run our own polling loop all the time as long as the receiver is started. The
 230  
              * blocking wait defined by VMConnector.getQueueTimeout() will prevent this worker's receiver
 231  
              * thread from busy-waiting.
 232  
              */
 233  0
             while (this.getReceiver().isConnected())
 234  
             {
 235  0
                 super.poll();
 236  
             }
 237  0
         }
 238  
     }
 239  
 
 240  
 }