View Javadoc

1   /*
2    * $Id: VMMessageReceiver.java 22742 2011-08-25 20:58:42Z dfeist $
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.MuleEvent;
15  import org.mule.api.MuleException;
16  import org.mule.api.MuleMessage;
17  import org.mule.api.ThreadSafeAccess;
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.ContinuousPollingReceiverWorker;
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.LinkedList;
30  import java.util.List;
31  import 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          super(connector, flowConstruct, endpoint);
46          this.setReceiveMessagesInTransaction(endpoint.getTransactionConfig().isTransacted());
47          this.connector = (VMConnector) connector;
48      }
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          if (!endpoint.getExchangePattern().hasResponse())
58          {
59              super.schedule();
60          }
61      }
62  
63      @Override
64      protected void doDispose()
65      {
66          // template method
67      }
68  
69      @Override
70      protected void doConnect() throws Exception
71      {
72          if (!endpoint.getExchangePattern().hasResponse())
73          {
74              // Ensure we can create a vm queue
75              QueueSession queueSession = connector.getQueueSession();
76              Queue q = queueSession.getQueue(endpoint.getEndpointURI().getAddress());
77              if (logger.isDebugEnabled())
78              {
79                  logger.debug("Current queue depth for queue: " + endpoint.getEndpointURI().getAddress() + " is: "
80                               + q.size());
81              }
82          }
83      }
84  
85      @Override
86      protected void doDisconnect() throws Exception
87      {
88          // template method
89      }
90  
91      public void onMessage(MuleMessage message) throws MuleException
92      {
93          // Rewrite the message to treat it as a new message
94          MuleMessage newMessage = new DefaultMuleMessage(message.getPayload(), message, connector.getMuleContext());
95          routeMessage(newMessage);
96      }
97  
98      public MuleMessage onCall(MuleMessage message) throws MuleException
99      {
100         MuleEvent event = null;
101         try
102         {
103             event = routeMessage(message);
104             MuleMessage returnedMessage = event == null ? null : event.getMessage();
105             if (returnedMessage != null)
106             {
107                 returnedMessage.release();
108             }
109             return returnedMessage;
110         }
111         catch (Exception e)
112         {
113             if (event == null)
114             {
115                 event = createMuleEvent(message, null);
116             }
117             return flowConstruct.getExceptionListener().handleException(e, event).getMessage();
118         }
119         finally
120         {
121             message.release();
122         }
123     }
124 
125     /**
126      * It's impossible to process all messages in the receive transaction
127      */
128     @Override
129     protected List<MuleMessage> getMessages() throws Exception
130     {
131         if (isReceiveMessagesInTransaction())
132         {
133             MuleEvent message = getFirstMessage();
134             if (message == null)
135             {
136                 return null;
137             }
138             
139             List<MuleMessage> messages = new ArrayList<MuleMessage>(1);
140             messages.add(message.getMessage());
141             return messages;
142         }
143         else
144         {
145             return getFirstMessages();
146         }
147     }
148     
149     protected List<MuleMessage> getFirstMessages() throws Exception
150     {
151         // The queue from which to pull events
152         QueueSession qs = connector.getQueueSession();
153         Queue queue = qs.getQueue(endpoint.getEndpointURI().getAddress());
154 
155         // The list of retrieved messages that will be returned
156         List<MuleMessage> messages = new LinkedList<MuleMessage>();
157 
158         int batchSize = getBatchSize(queue.size());
159 
160         // try to get the first event off the queue
161         MuleEvent message = (MuleEvent) queue.poll(connector.getQueueTimeout());
162 
163         if (message != null)
164         {
165             // keep first dequeued event
166             messages.add(message.getMessage());
167 
168             // keep batching if more events are available
169             for (int i = 0; i < batchSize && message != null; i++)
170             {
171                 message = (MuleEvent)queue.poll(0);
172                 if (message != null)
173                 {
174                     messages.add(message.getMessage());
175                 }
176             }
177         }
178 
179         // let our workManager handle the batch of events
180         return messages;
181     }
182     
183     protected MuleEvent getFirstMessage() throws Exception
184     {
185         // The queue from which to pull events
186         QueueSession qs = connector.getQueueSession();
187         Queue queue = qs.getQueue(endpoint.getEndpointURI().getAddress());
188         // try to get the first event off the queue
189         return (MuleEvent) queue.poll(connector.getQueueTimeout());
190     }
191 
192     @Override
193     protected boolean hasNoMessages()
194     {
195         try
196         {
197             QueueSession qs = connector.getQueueSession();
198             Queue queue = qs.getQueue(endpoint.getEndpointURI().getAddress());
199             return queue.peek() == null;
200         }
201         catch (Exception e)
202         {
203             return false;
204         }
205     }
206 
207     @Override
208     protected void processMessage(Object msg) throws Exception
209     {
210         MuleMessage message = (MuleMessage) msg;
211 
212         if (message instanceof ThreadSafeAccess)
213         {
214             message = (MuleMessage)((ThreadSafeAccess) message).newThreadCopy();
215         }
216         routeMessage(message);
217     }
218 
219     /*
220      * We create our own "polling" worker here since we need to evade the standard scheduler.
221      */
222     @Override
223     protected PollingReceiverWorker createWork()
224     {
225         return new ContinuousPollingReceiverWorker(this);
226     }    
227 }