View Javadoc

1   /*
2    * $Id: RemoteDispatcher.java 7963 2007-08-21 08:53:15Z dirk.olmes $
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.extras.client;
12  
13  import org.mule.MuleManager;
14  import org.mule.config.MuleProperties;
15  import org.mule.impl.MuleEvent;
16  import org.mule.impl.MuleMessage;
17  import org.mule.impl.MuleSession;
18  import org.mule.impl.MuleSessionHandler;
19  import org.mule.impl.RequestContext;
20  import org.mule.impl.endpoint.MuleEndpoint;
21  import org.mule.impl.internal.notifications.AdminNotification;
22  import org.mule.impl.security.MuleCredentials;
23  import org.mule.providers.AbstractConnector;
24  import org.mule.providers.service.TransportFactory;
25  import org.mule.transformers.wire.SerializationWireFormat;
26  import org.mule.transformers.wire.WireFormat;
27  import org.mule.umo.FutureMessageResult;
28  import org.mule.umo.UMOEvent;
29  import org.mule.umo.UMOException;
30  import org.mule.umo.UMOMessage;
31  import org.mule.umo.endpoint.UMOEndpoint;
32  import org.mule.umo.lifecycle.Disposable;
33  import org.mule.umo.provider.DispatchException;
34  import org.mule.umo.security.UMOCredentials;
35  import org.mule.util.MuleObjectHelper;
36  
37  import java.io.ByteArrayInputStream;
38  import java.io.ByteArrayOutputStream;
39  import java.io.InputStream;
40  import java.util.Map;
41  
42  import edu.emory.mathcs.backport.java.util.concurrent.Callable;
43  import edu.emory.mathcs.backport.java.util.concurrent.Executor;
44  import org.apache.commons.logging.Log;
45  import org.apache.commons.logging.LogFactory;
46  
47  /**
48   * <code>RemoteDispatcher</code> is used to make and receive requests to a remote
49   * Mule instance. It is used to proxy requests to Mule using the Server URL as the
50   * transport channel.
51   */
52  
53  public class RemoteDispatcher implements Disposable
54  {
55  
56      /**
57       * logger used by this class
58       */
59      protected static final Log logger = LogFactory.getLog(RemoteDispatcher.class);
60  
61      /**
62       * dispatch destination
63       */
64      private UMOEndpoint serverEndpoint;
65      private UMOCredentials credentials = null;
66  
67      /**
68       * an ExecutorService for async messages (optional)
69       */
70      private Executor asyncExecutor;
71  
72      /**
73       * calls made to a remote server are serialised using a wireformat
74       */
75      private WireFormat wireFormat;
76  
77      protected RemoteDispatcher(String endpoint, UMOCredentials credentials) throws UMOException
78      {
79          this(endpoint);
80          this.credentials = credentials;
81      }
82  
83      protected RemoteDispatcher(String endpoint) throws UMOException
84      {
85          serverEndpoint = new MuleEndpoint(endpoint, true);
86          wireFormat = new SerializationWireFormat();
87      }
88  
89      protected void setExecutor(Executor e)
90      {
91          this.asyncExecutor = e;
92      }
93  
94      /**
95       * Dispatcher an event asynchronously to a components on a remote Mule instance.
96       * Users can endpoint a url to a remote Mule server in the constructor of a Mule
97       * client, by default the default Mule server url tcp://localhost:60504 is used.
98       * 
99       * @param component the name of the Mule components to dispatch to
100      * @param payload the object that is the payload of the event
101      * @param messageProperties any properties to be associated with the payload. as
102      *            null
103      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
104      *             transfromers cannot be found
105      */
106     public void dispatchToRemoteComponent(String component, Object payload, Map messageProperties)
107         throws UMOException
108     {
109         doToRemoteComponent(component, payload, messageProperties, false);
110     }
111 
112     /**
113      * sends an event synchronously to a components on a remote Mule instance. Users
114      * can endpoint a url to a remote Mule server in the constructor of a Mule
115      * client, by default the default Mule server url tcp://localhost:60504 is used.
116      * 
117      * @param component the name of the Mule components to send to
118      * @param payload the object that is the payload of the event
119      * @param messageProperties any properties to be associated with the payload. as
120      *            null
121      * @return the result message if any of the invocation
122      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
123      *             transfromers cannot be found
124      */
125     public UMOMessage sendToRemoteComponent(String component, Object payload, Map messageProperties)
126         throws UMOException
127     {
128         return doToRemoteComponent(component, payload, messageProperties, true);
129     }
130 
131     /**
132      * sends an event to a components on a remote Mule instance, while making the
133      * result of the event trigger available as a Future result that can be accessed
134      * later by client code. Users can endpoint a url to a remote Mule server in the
135      * constructor of a Mule client, by default the default Mule server url
136      * tcp://localhost:60504 is used.
137      * 
138      * @param component the name of the Mule components to send to
139      * @param transformers a comma separated list of transformers to apply to the
140      *            result message
141      * @param payload the object that is the payload of the event
142      * @param messageProperties any properties to be associated with the payload. as
143      *            null
144      * @return the result message if any of the invocation
145      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
146      *             transfromers cannot be found
147      */
148     public FutureMessageResult sendAsyncToRemoteComponent(final String component,
149                                                           String transformers,
150                                                           final Object payload,
151                                                           final Map messageProperties) throws UMOException
152     {
153         Callable callable = new Callable()
154         {
155             public Object call() throws Exception
156             {
157                 return doToRemoteComponent(component, payload, messageProperties, true);
158             }
159         };
160 
161         FutureMessageResult result = new FutureMessageResult(callable);
162 
163         if (asyncExecutor != null)
164         {
165             result.setExecutor(asyncExecutor);
166         }
167 
168         if (transformers != null)
169         {
170             result.setTransformer(MuleObjectHelper.getTransformer(transformers, ","));
171         }
172 
173         result.execute();
174         return result;
175     }
176 
177     public UMOMessage sendRemote(String endpoint, Object payload, Map messageProperties, int timeout)
178         throws UMOException
179     {
180         return doToRemote(endpoint, payload, messageProperties, true, timeout);
181     }
182 
183     public UMOMessage sendRemote(String endpoint, Object payload, Map messageProperties) throws UMOException
184     {
185         return doToRemote(endpoint, payload, messageProperties, true, MuleManager.getConfiguration()
186             .getSynchronousEventTimeout());
187     }
188 
189     public void dispatchRemote(String endpoint, Object payload, Map messageProperties) throws UMOException
190     {
191         doToRemote(endpoint, payload, messageProperties, false, -1);
192     }
193 
194     public FutureMessageResult sendAsyncRemote(final String endpoint,
195                                                final Object payload,
196                                                final Map messageProperties) throws UMOException
197     {
198         Callable callable = new Callable()
199         {
200             public Object call() throws Exception
201             {
202                 return doToRemote(endpoint, payload, messageProperties, true, -1);
203             }
204         };
205 
206         FutureMessageResult result = new FutureMessageResult(callable);
207 
208         if (asyncExecutor != null)
209         {
210             result.setExecutor(asyncExecutor);
211         }
212 
213         result.execute();
214         return result;
215     }
216 
217     public UMOMessage receiveRemote(String endpoint, int timeout) throws UMOException
218     {
219         AdminNotification action = new AdminNotification(null, AdminNotification.ACTION_RECEIVE, endpoint);
220         action.setProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, "true");
221         action.setProperty(MuleProperties.MULE_EVENT_TIMEOUT_PROPERTY, new Long(timeout));
222         UMOMessage result = dispatchAction(action, true, timeout);
223         return result;
224     }
225 
226     public FutureMessageResult asyncReceiveRemote(final String endpoint, final int timeout)
227         throws UMOException
228     {
229         Callable callable = new Callable()
230         {
231             public Object call() throws Exception
232             {
233                 return receiveRemote(endpoint, timeout);
234             }
235         };
236 
237         FutureMessageResult result = new FutureMessageResult(callable);
238 
239         if (asyncExecutor != null)
240         {
241             result.setExecutor(asyncExecutor);
242         }
243 
244         result.execute();
245         return result;
246     }
247 
248     protected UMOMessage doToRemoteComponent(String component,
249                                              Object payload,
250                                              Map messageProperties,
251                                              boolean synchronous) throws UMOException
252     {
253         UMOMessage message = new MuleMessage(payload, messageProperties);
254         message.setBooleanProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, synchronous);
255         setCredentials(message);
256         AdminNotification action = new AdminNotification(message, AdminNotification.ACTION_INVOKE,
257             "mule://" + component);
258         UMOMessage result = dispatchAction(action, synchronous, MuleManager.getConfiguration()
259             .getSynchronousEventTimeout());
260         return result;
261     }
262 
263     protected UMOMessage doToRemote(String endpoint,
264                                     Object payload,
265                                     Map messageProperties,
266                                     boolean synchronous,
267                                     int timeout) throws UMOException
268     {
269         UMOMessage message = new MuleMessage(payload, messageProperties);
270         message.setProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, String.valueOf(synchronous));
271         setCredentials(message);
272         AdminNotification action = new AdminNotification(message, (synchronous
273                         ? AdminNotification.ACTION_SEND : AdminNotification.ACTION_DISPATCH), endpoint);
274 
275         UMOMessage result = dispatchAction(action, synchronous, timeout);
276         return result;
277     }
278 
279     protected UMOMessage dispatchAction(AdminNotification action, boolean synchronous, int timeout)
280         throws UMOException
281     {
282 
283         UMOEndpoint endpoint = TransportFactory.createEndpoint(serverEndpoint.getEndpointURI(),
284             UMOEndpoint.ENDPOINT_TYPE_SENDER);
285         endpoint.setRemoteSync(synchronous);
286         updateContext(new MuleMessage(action), endpoint, synchronous);
287 
288         ByteArrayOutputStream out = new ByteArrayOutputStream();
289         wireFormat.write(out, action);
290         byte[] payload = out.toByteArray();
291 
292         UMOMessage message = action.getMessage();
293 
294         if (message == null)
295         {
296             message = new MuleMessage(payload);
297         }
298         else
299         {
300             message = new MuleMessage(payload, message);
301         }
302 
303         message.addProperties(action.getProperties());
304         MuleSession session = new MuleSession(message,
305             ((AbstractConnector)endpoint.getConnector()).getSessionHandler());
306 
307         UMOEvent event = new MuleEvent(message, endpoint, session, true);
308         event.setTimeout(timeout);
309         if (logger.isDebugEnabled())
310         {
311             logger.debug("MuleClient sending remote call to: " + action.getResourceIdentifier() + ". At "
312                          + serverEndpoint.toString() + " . Event is: " + event);
313         }
314 
315         UMOMessage result;
316 
317         try
318         {
319             if (synchronous)
320             {
321                 result = endpoint.send(event);
322             }
323             else
324             {
325                 endpoint.dispatch(event);
326                 return null;
327             }
328 
329             if (result != null)
330             {
331                 if (result.getPayload() != null)
332                 {
333                     Object response;
334                     if (result.getPayload() instanceof InputStream)
335                     {
336                         response = wireFormat.read((InputStream)result.getPayload());
337                     }
338                     else
339                     {
340                         ByteArrayInputStream in = new ByteArrayInputStream(result.getPayloadAsBytes());
341                         response = wireFormat.read(in);
342                     }
343 
344                     if (response instanceof AdminNotification)
345                     {
346                         response = ((AdminNotification)response).getMessage();
347                     }
348                     return (UMOMessage)response;
349                 }
350             }
351         }
352         catch (Exception e)
353         {
354             throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
355         }
356 
357         if (logger.isDebugEnabled())
358         {
359             logger.debug("Result of MuleClient remote call is: "
360                          + (result == null ? "null" : result.getPayload()));
361         }
362 
363         return result;
364     }
365 
366     public void dispose()
367     {
368         // nothing to do here
369     }
370 
371     protected void setCredentials(UMOMessage message)
372     {
373         if (credentials != null)
374         {
375             message.setProperty(MuleProperties.MULE_USER_PROPERTY, MuleCredentials.createHeader(
376                 credentials.getUsername(), credentials.getPassword()));
377         }
378     }
379 
380     public WireFormat getWireFormat()
381     {
382         return wireFormat;
383     }
384 
385     public void setWireFormat(WireFormat wireFormat)
386     {
387         this.wireFormat = wireFormat;
388     }
389 
390     protected void updateContext(UMOMessage message, UMOEndpoint endpoint, boolean synchronous)
391         throws UMOException
392     {
393 
394         RequestContext.setEvent(new MuleEvent(message, endpoint, new MuleSession(message,
395             new MuleSessionHandler()), synchronous));
396     }
397 }