View Javadoc

1   /*
2    * $Id: VMMessageDispatcher.java 10524 2008-01-24 19:20:11Z akuzmin $
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.MuleManager;
14  import org.mule.config.i18n.CoreMessages;
15  import org.mule.impl.MuleMessage;
16  import org.mule.providers.AbstractMessageDispatcher;
17  import org.mule.providers.vm.i18n.VMMessages;
18  import org.mule.transaction.TransactionCallback;
19  import org.mule.transaction.TransactionTemplate;
20  import org.mule.transformers.simple.ObjectToByteArray;
21  import org.mule.umo.UMOEvent;
22  import org.mule.umo.UMOMessage;
23  import org.mule.umo.endpoint.UMOEndpointURI;
24  import org.mule.umo.endpoint.UMOImmutableEndpoint;
25  import org.mule.umo.provider.DispatchException;
26  import org.mule.umo.provider.NoReceiverForEndpointException;
27  import org.mule.umo.provider.UMOStreamMessageAdapter;
28  import org.mule.util.queue.Queue;
29  import org.mule.util.queue.QueueSession;
30  
31  import java.io.ByteArrayInputStream;
32  import java.io.InputStream;
33  import java.io.PipedInputStream;
34  import java.io.PipedOutputStream;
35  
36  /**
37   * <code>VMMessageDispatcher</code> is used for providing in memory interaction
38   * between components.
39   */
40  public class VMMessageDispatcher extends AbstractMessageDispatcher
41  {
42      private final VMConnector connector;
43      private final ObjectToByteArray objectToByteArray;
44  
45      public VMMessageDispatcher(UMOImmutableEndpoint endpoint)
46      {
47          super(endpoint);
48          this.connector = (VMConnector) endpoint.getConnector();
49          objectToByteArray = new ObjectToByteArray();
50      }
51  
52      /**
53       * Make a specific request to the underlying transport
54       *
55       * @param timeout the maximum time the operation should block before returning.
56       *                The call should return immediately if there is data available. If
57       *                no data becomes available before the timeout elapses, null will be
58       *                returned
59       * @return the result of the request wrapped in a UMOMessage object. Null will be
60       *         returned if no data was available
61       * @throws Exception if the call to the underlying protocol causes an exception
62       */
63      protected UMOMessage doReceive(long timeout) throws Exception
64      {
65          if (!connector.isQueueEvents())
66          {
67              throw new UnsupportedOperationException("Receive requested on VM Connector, but queueEvents is false");
68          }
69  
70          try
71          {
72              QueueSession queueSession = connector.getQueueSession();
73              Queue queue = queueSession.getQueue(endpoint.getEndpointURI().getAddress());
74  
75              if (queue == null)
76              {
77                  if (logger.isDebugEnabled())
78                  {
79                      logger.debug("No queue with name " + endpoint.getEndpointURI().getAddress());
80                  }
81                  return null;
82              }
83              else
84              {
85                  UMOEvent event = null;
86                  if (logger.isDebugEnabled())
87                  {
88                      logger.debug("Waiting for a message on " + endpoint.getEndpointURI().getAddress());
89                  }
90                  try
91                  {
92                      event = (UMOEvent) queue.poll(timeout);
93                  }
94                  catch (InterruptedException e)
95                  {
96                      logger.error("Failed to receive event from queue: " + endpoint.getEndpointURI());
97                  }
98                  if (event != null)
99                  {
100                     if (logger.isDebugEnabled())
101                     {
102                         logger.debug("Event received: " + event);
103                     }
104                     return event.getMessage();
105                 }
106                 else
107                 {
108                     if (logger.isDebugEnabled())
109                     {
110                         logger.debug("No event received after " + timeout + " ms");
111                     }
112                     return null;
113                 }
114             }
115         }
116         catch (Exception e)
117         {
118             throw e;
119         }
120     }
121 
122     protected void doDispatch(final UMOEvent event) throws Exception
123     {
124         UMOEndpointURI endpointUri = event.getEndpoint().getEndpointURI();
125 
126         // because this is vm th emessage will not be serialized, even though it will
127         // be passed to a new thread.  so we need to generate a new copy of the message
128         // at this point
129         //event = event.newCopy();
130         // doesn't help needs to be later?
131 
132         if (endpointUri == null)
133         {
134             throw new DispatchException(
135                     CoreMessages.objectIsNull("Endpoint"), event.getMessage(), event.getEndpoint());
136         }
137         if (connector.isQueueEvents())
138         {
139             QueueSession session = connector.getQueueSession();
140             Queue queue = session.getQueue(endpointUri.getAddress());
141             queue.put(event);
142         }
143         else
144         {
145             final VMMessageReceiver receiver = connector.getReceiver(event.getEndpoint().getEndpointURI());
146             if (receiver == null)
147             {
148                 logger.warn("No receiver for endpointUri: " + event.getEndpoint().getEndpointURI());
149                 return;
150             }
151 
152             if (event.isStreaming())
153             {
154                 PipedInputStream in = new PipedInputStream();
155                 PipedOutputStream out = new PipedOutputStream(in);
156                 UMOStreamMessageAdapter sma = connector.getStreamMessageAdapter(in, out);
157                 sma.write(event);
158             }
159             TransactionTemplate tt = new TransactionTemplate(receiver.getEndpoint().getTransactionConfig(), connector
160                     .getExceptionListener());
161 
162             TransactionCallback cb = new TransactionCallback()
163             {
164                 public Object doInTransaction() throws Exception
165                 {
166                     receiver.onEvent(event);
167                     return null;
168                 }
169             };
170             tt.execute(cb);
171         }
172         if (logger.isDebugEnabled())
173         {
174             logger.debug("dispatched Event on endpointUri: " + endpointUri);
175         }
176     }
177 
178     protected UMOMessage doSend(final UMOEvent event) throws Exception
179     {
180         UMOMessage retMessage = null;
181         UMOEndpointURI endpointUri = event.getEndpoint().getEndpointURI();
182         final VMMessageReceiver receiver = connector.getReceiver(endpointUri);
183         if (receiver == null)
184         {
185             if (connector.isQueueEvents())
186             {
187                 if (logger.isDebugEnabled())
188                 {
189                     logger.debug("Writing to queue as there is no receiver on connector: "
190                                  + connector.getName() + ", for endpointUri: "
191                                  + event.getEndpoint().getEndpointURI());
192                 }
193                 doDispatch(event);
194                 return null;
195             }
196             else
197             {
198                 throw new NoReceiverForEndpointException(
199                         VMMessages.noReceiverForEndpoint(connector.getName(),
200                                                          event.getEndpoint().getEndpointURI()));
201             }
202         }
203         if (event.isStreaming())
204         {
205             PipedInputStream in = new PipedInputStream();
206             PipedOutputStream out = new PipedOutputStream(in);
207             UMOStreamMessageAdapter sma = connector.getStreamMessageAdapter(in, out);
208             sma.write(event);
209         }
210 
211         TransactionTemplate tt = new TransactionTemplate(receiver.getEndpoint().getTransactionConfig(), connector
212                 .getExceptionListener());
213 
214         TransactionCallback cb = new TransactionCallback()
215         {
216             public Object doInTransaction() throws Exception
217             {
218                 return receiver.onCall(event);
219             }
220         };
221         retMessage = (UMOMessage) tt.execute(cb);
222 
223         if (event.isStreaming() && retMessage != null)
224         {
225             InputStream in;
226             if (retMessage.getPayload() instanceof InputStream)
227             {
228                 in = (InputStream) retMessage.getPayload();
229             }
230             else
231             {
232                 in = new ByteArrayInputStream((byte[]) objectToByteArray.transform(retMessage.getPayload()));
233             }
234             UMOStreamMessageAdapter sma = connector.getStreamMessageAdapter(in, null);
235             retMessage = new MuleMessage(sma, retMessage);
236         }
237 
238         if (logger.isDebugEnabled())
239         {
240             logger.debug("sent event on endpointUri: " + event.getEndpoint().getEndpointURI());
241         }
242 
243         return retMessage;
244     }
245 
246     protected void doDispose()
247     {
248         // template method
249     }
250 
251     protected void doConnect() throws Exception
252     {
253         if (connector.isQueueEvents())
254         {
255             // use the default queue profile to configure this queue.
256             // Todo We may want to allow users to specify this at the connector level
257             MuleManager.getConfiguration().getQueueProfile().configureQueue(
258                     endpoint.getEndpointURI().getAddress());
259         }
260     }
261 
262     protected void doDisconnect() throws Exception
263     {
264         // template method
265     }
266 
267 }