View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.transport.vm;
8   
9   import org.mule.DefaultMuleMessage;
10  import org.mule.api.DefaultMuleException;
11  import org.mule.api.MuleEvent;
12  import org.mule.api.MuleException;
13  import org.mule.api.MuleMessage;
14  import org.mule.api.construct.FlowConstruct;
15  import org.mule.api.endpoint.InboundEndpoint;
16  import org.mule.api.lifecycle.CreateException;
17  import org.mule.api.transport.Connector;
18  import org.mule.transport.ContinuousPollingReceiverWorker;
19  import org.mule.transport.PollingReceiverWorker;
20  import org.mule.transport.TransactedPollingMessageReceiver;
21  import org.mule.util.queue.Queue;
22  import org.mule.util.queue.QueueSession;
23  
24  import java.util.ArrayList;
25  import java.util.LinkedList;
26  import java.util.List;
27  
28  import edu.emory.mathcs.backport.java.util.concurrent.RejectedExecutionException;
29  
30  /**
31   * <code>VMMessageReceiver</code> is a listener for events from a Mule service which then simply passes
32   * the events on to the target service.
33   */
34  public class VMMessageReceiver extends TransactedPollingMessageReceiver
35  {
36  
37      private VMConnector connector;
38  
39      public VMMessageReceiver(Connector connector, FlowConstruct flowConstruct, InboundEndpoint endpoint)
40          throws CreateException
41      {
42          super(connector, flowConstruct, endpoint);
43          this.setReceiveMessagesInTransaction(endpoint.getTransactionConfig().isTransacted());
44          this.connector = (VMConnector) connector;
45      }
46  
47      /*
48       * We only need to start scheduling this receiver if event queueing is enabled on the connector; otherwise
49       * events are delivered via onEvent/onCall.
50       */
51      @Override
52      protected void schedule() throws RejectedExecutionException, NullPointerException, IllegalArgumentException
53      {
54          if (!endpoint.getExchangePattern().hasResponse())
55          {
56              super.schedule();
57          }
58      }
59  
60      @Override
61      protected void doDispose()
62      {
63          // template method
64      }
65  
66      @Override
67      protected void doConnect() throws Exception
68      {
69          if (!endpoint.getExchangePattern().hasResponse())
70          {
71              // Ensure we can create a vm queue
72              QueueSession queueSession = connector.getQueueSession();
73              Queue q = queueSession.getQueue(endpoint.getEndpointURI().getAddress());
74              if (logger.isDebugEnabled())
75              {
76                  logger.debug("Current queue depth for queue: " + endpoint.getEndpointURI().getAddress() + " is: "
77                               + q.size());
78              }
79          }
80      }
81  
82      @Override
83      protected void doDisconnect() throws Exception
84      {
85          // template method
86      }
87  
88      public void onMessage(MuleMessage message) throws MuleException
89      {
90          // Rewrite the message to treat it as a new message
91          MuleMessage newMessage = new DefaultMuleMessage(message.getPayload(), message, connector.getMuleContext());
92          routeMessage(newMessage);
93      }
94  
95      public MuleMessage onCall(MuleMessage message) throws MuleException
96      {
97          try
98          {
99              // Rewrite the message to treat it as a new message
100             MuleMessage newMessage = message.createInboundMessage();
101             MuleEvent event =  routeMessage(newMessage);
102             MuleMessage returnedMessage = event == null ? null : event.getMessage();
103             if (returnedMessage != null)
104             {
105                 returnedMessage = returnedMessage.createInboundMessage();
106                 returnedMessage.release();
107             }
108             return returnedMessage;
109         }
110         catch (Exception e)
111         {
112             throw new DefaultMuleException(e);
113         }
114         finally
115         {
116             message.release();
117         }
118     }
119 
120     /**
121      * It's impossible to process all messages in the receive transaction
122      */
123     @Override
124     protected List<MuleMessage> getMessages() throws Exception
125     {
126         if (isReceiveMessagesInTransaction())
127         {
128             MuleEvent message = getFirstMessage();
129             if (message == null)
130             {
131                 return null;
132             }
133             
134             List<MuleMessage> messages = new ArrayList<MuleMessage>(1);
135             messages.add(message.getMessage());
136             return messages;
137         }
138         else
139         {
140             return getFirstMessages();
141         }
142     }
143     
144     protected List<MuleMessage> getFirstMessages() throws Exception
145     {
146         // The queue from which to pull events
147         QueueSession qs = connector.getQueueSession();
148         Queue queue = qs.getQueue(endpoint.getEndpointURI().getAddress());
149 
150         // The list of retrieved messages that will be returned
151         List<MuleMessage> messages = new LinkedList<MuleMessage>();
152 
153         int batchSize = getBatchSize(queue.size());
154 
155         // try to get the first event off the queue
156         MuleEvent message = (MuleEvent) queue.poll(connector.getQueueTimeout());
157 
158         if (message != null)
159         {
160             // keep first dequeued event
161             messages.add(message.getMessage());
162 
163             // keep batching if more events are available
164             for (int i = 0; i < batchSize && message != null; i++)
165             {
166                 message = (MuleEvent)queue.poll(0);
167                 if (message != null)
168                 {
169                     messages.add(message.getMessage());
170                 }
171             }
172         }
173 
174         // let our workManager handle the batch of events
175         return messages;
176     }
177     
178     protected MuleEvent getFirstMessage() throws Exception
179     {
180         // The queue from which to pull events
181         QueueSession qs = connector.getQueueSession();
182         Queue queue = qs.getQueue(endpoint.getEndpointURI().getAddress());
183         // try to get the first event off the queue
184         return (MuleEvent) queue.poll(connector.getQueueTimeout());
185     }
186 
187     @Override
188     protected void processMessage(Object msg) throws Exception
189     {
190         MuleMessage message = (MuleMessage) msg;
191 
192         // Rewrite the message to treat it as a new message
193         MuleMessage newMessage = message.createInboundMessage();
194         routeMessage(newMessage);
195     }
196 
197     /*
198      * We create our own "polling" worker here since we need to evade the standard scheduler.
199      */
200     @Override
201     protected PollingReceiverWorker createWork()
202     {
203         return new ContinuousPollingReceiverWorker(this);
204     }    
205 }