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