View Javadoc

1   /*
2    * $Id: MuleClient.java 7976 2007-08-21 14:26:13Z 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.ConfigurationBuilder;
15  import org.mule.config.ConfigurationException;
16  import org.mule.config.MuleConfiguration;
17  import org.mule.config.MuleProperties;
18  import org.mule.config.builders.MuleXmlConfigurationBuilder;
19  import org.mule.config.builders.QuickConfigurationBuilder;
20  import org.mule.config.i18n.CoreMessages;
21  import org.mule.extras.client.i18n.ClientMessages;
22  import org.mule.impl.MuleEvent;
23  import org.mule.impl.MuleMessage;
24  import org.mule.impl.MuleSession;
25  import org.mule.impl.endpoint.MuleEndpoint;
26  import org.mule.impl.endpoint.MuleEndpointURI;
27  import org.mule.impl.model.ModelHelper;
28  import org.mule.impl.security.MuleCredentials;
29  import org.mule.providers.AbstractConnector;
30  import org.mule.providers.service.TransportFactory;
31  import org.mule.umo.FutureMessageResult;
32  import org.mule.umo.MessagingException;
33  import org.mule.umo.UMODescriptor;
34  import org.mule.umo.UMOEvent;
35  import org.mule.umo.UMOException;
36  import org.mule.umo.UMOMessage;
37  import org.mule.umo.UMOSession;
38  import org.mule.umo.endpoint.UMOEndpoint;
39  import org.mule.umo.endpoint.UMOEndpointURI;
40  import org.mule.umo.lifecycle.Disposable;
41  import org.mule.umo.manager.UMOManager;
42  import org.mule.umo.provider.DispatchException;
43  import org.mule.umo.provider.ReceiveException;
44  import org.mule.umo.provider.UMOConnector;
45  import org.mule.umo.provider.UMOStreamMessageAdapter;
46  import org.mule.umo.transformer.UMOTransformer;
47  import org.mule.util.MuleObjectHelper;
48  import org.mule.util.StringUtils;
49  
50  import java.util.ArrayList;
51  import java.util.HashMap;
52  import java.util.Iterator;
53  import java.util.List;
54  import java.util.Map;
55  
56  import edu.emory.mathcs.backport.java.util.concurrent.Callable;
57  import edu.emory.mathcs.backport.java.util.concurrent.Executor;
58  import org.apache.commons.logging.Log;
59  import org.apache.commons.logging.LogFactory;
60  
61  /**
62   * <code>MuleClient</code> is a simple interface for Mule clients to send and
63   * receive events from a Mule Server. In most Mule applications events are triggered
64   * by some external occurrence such as a message being received on a queue or file
65   * being copied to a directory. The Mule client allows the user to send and receive
66   * events programmatically through its Api.
67   * <p>
68   * The client defines a UMOEndpointURI which is used to determine how a message is
69   * sent of received. The url defines the protocol, the endpointUri destination of the
70   * message and optionally the endpoint to use when dispatching the event. For
71   * example:
72   * <p>
73   * <code>vm://my.object</code> dispatches to a <code>my.object</code> destination
74   * using the VM endpoint. There needs to be a global VM endpoint registered for the
75   * message to be sent.
76   * <p>
77   * <code>jms://jmsProvider/orders.topic</code> dispatches a JMS message via the
78   * globally registered jmsProvider over a topic destination called
79   * <code>orders.topic</code>.
80   * <p>
81   * <code>jms://orders.topic</code> is equivalent to the above except that the
82   * endpoint is determined by the protocol, so the first JMS endpoint is used.
83   * <p>
84   * Note that there must be a configured MuleManager for this client to work. It will
85   * use the one available using <code>MuleManager.getInstance()</code>
86   * 
87   * @see org.mule.impl.endpoint.MuleEndpointURI
88   */
89  public class MuleClient implements Disposable
90  {
91      /**
92       * logger used by this class
93       */
94      protected static final Log logger = LogFactory.getLog(MuleClient.class);
95  
96      /**
97       * the local UMOManager instance
98       */
99      private UMOManager manager;
100 
101     /**
102      * an Executor for async messages (optional), currently always delegated to
103      * MuleManager's default WorkManager
104      */
105     private Executor asyncExecutor = null;
106 
107     private List dispatchers = new ArrayList();
108 
109     // configuration helper for the client
110     QuickConfigurationBuilder builder = null;
111 
112     private MuleCredentials user;
113 
114     /**
115      * Creates a default Mule client that will use the default serverEndpoint to
116      * connect to a remote server instance.
117      * 
118      * @throws UMOException
119      */
120     public MuleClient() throws UMOException
121     {
122         init(/* startManager */true);
123     }
124 
125     /**
126      * Creates a default Mule client that will use the default serverEndpoint to
127      * connect to a remote server instance.
128      * 
129      * @param startManager start the Mule Manager if it has not yet been initialised
130      * @throws UMOException
131      */
132     public MuleClient(boolean startManager) throws UMOException
133     {
134         init(startManager);
135     }
136 
137     /**
138      * Configures a Mule CLient instance using the the default
139      * MuleXmlConfigurationBuilder to parse the config resources
140      * 
141      * @param configResources a config resource location to configure this client
142      *            with
143      * @throws ConfigurationException is there is a MuleManager instance already
144      *             running in this JVM or if the builder fails to configure the
145      *             Manager
146      */
147     public MuleClient(String configResources) throws UMOException
148     {
149         this(configResources, new MuleXmlConfigurationBuilder());
150     }
151 
152     /**
153      * Configures a new MuleClient and either uses an existing Manager running in
154      * this JVM or creates a new empty manager
155      * 
156      * @param user the username to use when connecting to a remote server instance
157      * @param password the password for the user
158      * @throws UMOException
159      */
160     public MuleClient(String user, String password) throws UMOException
161     {
162         init(/* startManager */true);
163         this.user = new MuleCredentials(user, password.toCharArray());
164     }
165 
166     /**
167      * Configures a Mule Client instance
168      * 
169      * @param configResources a config resource location to configure this client
170      *            with
171      * @param builder the configuration builder to use
172      * @throws ConfigurationException is there is a MuleManager instance already
173      *             running in this JVM or if the builder fails to configure the
174      *             Manager
175      */
176     public MuleClient(String configResources, ConfigurationBuilder builder) throws ConfigurationException
177     {
178         if (MuleManager.isInstanciated())
179         {
180             throw new ConfigurationException(ClientMessages.managerIsAlreadyConfigured());
181         }
182         if (builder == null)
183         {
184             logger.info("Builder passed in was null, using default builder: "
185                         + MuleXmlConfigurationBuilder.class.getName());
186             builder = new MuleXmlConfigurationBuilder();
187         }
188         manager = builder.configure(configResources, null);
189     }
190 
191     /**
192      * Configures a Mule Client instance
193      * 
194      * @param configResources a config resource location to configure this client
195      *            with
196      * @param builder the configuration builder to use
197      * @param user the username to use when connecting to a remote server instance
198      * @param password the password for the user
199      * @throws ConfigurationException is there is a MuleManager instance already
200      *             running in this JVM or if the builder fails to configure the
201      *             Manager
202      */
203     public MuleClient(String configResources, ConfigurationBuilder builder, String user, String password)
204         throws ConfigurationException
205     {
206         this(configResources, builder);
207         this.user = new MuleCredentials(user, password.toCharArray());
208     }
209 
210     /**
211      * Initialises a default MuleManager for use by the client.
212      * 
213      * @param startManager start the Mule Manager if it has not yet been initialised
214      * @throws UMOException
215      */
216     private void init(boolean startManager) throws UMOException
217     {
218         // if we are creating a server for this client then set client mode
219         // this will disable Admin connections by default;
220         // If there is no local manager present create a default manager
221         if (MuleManager.isInstanciated())
222         {
223             if (logger.isInfoEnabled())
224             {
225                 logger.info("There is already a manager locally available to this client, no need to create a new one");
226             }
227         }
228         else
229         {
230             MuleManager.getConfiguration().setClientMode(true);
231             if (logger.isInfoEnabled())
232             {
233                 logger.info("There is no manager instance locally available for this client, creating a new Manager");
234             }
235         }
236 
237         manager = MuleManager.getInstance();
238         asyncExecutor = manager.getWorkManager();
239         builder = new QuickConfigurationBuilder();
240 
241         if (!manager.isInitialised() && startManager == true)
242         {
243             if (logger.isInfoEnabled()) logger.info("Starting Mule Manager for this client");
244             ((MuleManager)manager).start();
245         }
246     }
247 
248     /**
249      * Dispatches an event asynchronously to a endpointUri via a mule server. the Url
250      * determines where to dispathc the event to, this can be in the form of
251      * 
252      * @param url the Mule url used to determine the destination and transport of the
253      *            message
254      * @param payload the object that is the payload of the event
255      * @param messageProperties any properties to be associated with the payload. In
256      *            the case of Jms you could set the JMSReplyTo property in these
257      *            properties.
258      * @throws org.mule.umo.UMOException
259      */
260     public void dispatch(String url, Object payload, Map messageProperties) throws UMOException
261     {
262         dispatch(url, new MuleMessage(payload, messageProperties));
263     }
264 
265     /**
266      * Dispatches an event asynchronously to a endpointUri via a mule server. the Url
267      * determines where to dispathc the event to, this can be in the form of
268      * 
269      * @param url the Mule url used to determine the destination and transport of the
270      *            message
271      * @param message the message to send
272      * @throws org.mule.umo.UMOException
273      */
274     public void dispatch(String url, UMOMessage message) throws UMOException
275     {
276         UMOEvent event = getEvent(message, url, false, false);
277         try
278         {
279             event.getSession().dispatchEvent(event);
280         }
281         catch (UMOException e)
282         {
283             throw e;
284         }
285         catch (Exception e)
286         {
287             throw new DispatchException(ClientMessages.failedToDispatchClientEvent(), 
288                 event.getMessage(), event.getEndpoint(), e);
289         }
290     }
291 
292     /**
293      * Dispatches a Stream event asynchronously to a endpointUri via a mule server.
294      * the Url determines where to dispathc the event to, this can be in the form of
295      * 
296      * @param url the Mule url used to determine the destination and transport of the
297      *            message
298      * @param message the message to send
299      * @throws org.mule.umo.UMOException
300      */
301     public void dispatchStream(String url, UMOStreamMessageAdapter message) throws UMOException
302     {
303         UMOEvent event = getEvent(new MuleMessage(message), url, false, true);
304         try
305         {
306             event.getSession().dispatchEvent(event);
307         }
308         catch (UMOException e)
309         {
310             throw e;
311         }
312         catch (Exception e)
313         {
314             throw new DispatchException(ClientMessages.failedToDispatchClientEvent(), 
315                 event.getMessage(), event.getEndpoint(), e);
316         }
317     }
318 
319     public UMOStreamMessageAdapter sendStream(String url, UMOStreamMessageAdapter message)
320         throws UMOException
321     {
322         return sendStream(url, message, UMOEvent.TIMEOUT_NOT_SET_VALUE);
323     }
324 
325     /**
326      * Sends a streaming event synchronously to a endpointUri via a mule server and a
327      * resulting stream is set on the passed Stream Mesage Adapter.
328      * 
329      * @param url the Mule url used to determine the destination and transport of the
330      *            message
331      * @param message The message to send
332      * @param timeout The time in milliseconds the the call should block waiting for
333      *            a response
334      * @throws org.mule.umo.UMOException
335      */
336     public UMOStreamMessageAdapter sendStream(String url, UMOStreamMessageAdapter message, int timeout)
337         throws UMOException
338     {
339         UMOEvent event = getEvent(new MuleMessage(message), url, true, true);
340         event.setTimeout(timeout);
341         try
342         {
343             UMOMessage result = event.getSession().sendEvent(event);
344             if (result != null)
345             {
346                 if (result.getAdapter() instanceof UMOStreamMessageAdapter)
347                 {
348                     return (UMOStreamMessageAdapter)result.getAdapter();
349                 }
350                 else
351                 {
352                     // todo i18n (though this case should never happen...)
353                     throw new IllegalStateException(
354                         "Mismatch of stream states. A stream was used for outbound channel, but a stream was not used for the response");
355                 }
356             }
357         }
358         catch (UMOException e)
359         {
360             throw e;
361         }
362         catch (Exception e)
363         {
364             throw new DispatchException(ClientMessages.failedToDispatchClientEvent(), 
365                 event.getMessage(), event.getEndpoint(), e);
366         }
367         return null;
368     }
369 
370     /**
371      * sends an event synchronously to a components
372      * 
373      * @param component the name of the Mule components to send to
374      * @param transformers a comma separated list of transformers to apply to the
375      *            result message
376      * @param payload the object that is the payload of the event
377      * @param messageProperties any properties to be associated with the payload. as
378      *            null
379      * @return the result message if any of the invocation
380      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
381      *             transfromers cannot be found
382      */
383     public UMOMessage sendDirect(String component, String transformers, Object payload, Map messageProperties)
384         throws UMOException
385     {
386         UMOMessage message = new MuleMessage(payload, messageProperties);
387         return sendDirect(component, transformers, message);
388     }
389 
390     /**
391      * sends an event synchronously to a components
392      * 
393      * @param component the name of the Mule components to send to
394      * @param transformers a comma separated list of transformers to apply to the
395      *            result message
396      * @param message the message to send
397      * @return the result message if any of the invocation
398      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
399      *             transfromers cannot be found
400      */
401     public UMOMessage sendDirect(String component, String transformers, UMOMessage message)
402         throws UMOException
403     {
404         boolean compregistered = ModelHelper.isComponentRegistered(component);
405         if (!compregistered)
406         {
407             throw new MessagingException(
408                 CoreMessages.objectNotRegisteredWithManager("Component '" + component + "'"), 
409                 message, null);
410         }
411         UMOTransformer trans = null;
412         if (transformers != null)
413         {
414             trans = MuleObjectHelper.getTransformer(transformers, ",");
415         }
416 
417         if (!MuleManager.getConfiguration().isSynchronous())
418         {
419             logger.warn("The mule manager is running synchronously, a null message payload will be returned");
420         }
421         UMOSession session = new MuleSession(ModelHelper.getComponent(component));
422         UMOEndpoint endpoint = getDefaultClientEndpoint(session.getComponent().getDescriptor(),
423             message.getPayload());
424         UMOEvent event = new MuleEvent(message, endpoint, session, true);
425 
426         if (logger.isDebugEnabled())
427         {
428             logger.debug("MuleClient sending event direct to: " + component + ". Event is: " + event);
429         }
430 
431         UMOMessage result = event.getComponent().sendEvent(event);
432 
433         if (logger.isDebugEnabled())
434         {
435             logger.debug("Result of MuleClient sendDirect is: "
436                          + (result == null ? "null" : result.getPayload()));
437         }
438 
439         if (result != null && trans != null)
440         {
441             return new MuleMessage(trans.transform(result.getPayload()));
442         }
443         else
444         {
445             return result;
446         }
447     }
448 
449     /**
450      * dispatches an event asynchronously to the components
451      * 
452      * @param component the name of the Mule components to dispatch to
453      * @param payload the object that is the payload of the event
454      * @param messageProperties any properties to be associated with the payload. as
455      *            null
456      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
457      *             transfromers cannot be found
458      */
459     public void dispatchDirect(String component, Object payload, Map messageProperties) throws UMOException
460     {
461         dispatchDirect(component, new MuleMessage(payload, messageProperties));
462     }
463 
464     /**
465      * dispatches an event asynchronously to the components
466      * 
467      * @param component the name of the Mule components to dispatch to
468      * @param message the message to send
469      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
470      *             transfromers cannot be found
471      */
472     public void dispatchDirect(String component, UMOMessage message) throws UMOException
473     {
474         boolean compregistered = ModelHelper.isComponentRegistered(component);
475         if (!compregistered)
476         {
477             throw new MessagingException(
478                 CoreMessages.objectNotRegisteredWithManager("Component '" + component + "'"), 
479                 message, null);
480         }
481         UMOSession session = new MuleSession(ModelHelper.getComponent(component));
482         UMOEndpoint endpoint = getDefaultClientEndpoint(session.getComponent().getDescriptor(),
483             message.getPayload());
484         UMOEvent event = new MuleEvent(message, endpoint, session, true);
485 
486         if (logger.isDebugEnabled())
487         {
488             logger.debug("MuleClient dispatching event direct to: " + component + ". Event is: " + event);
489         }
490 
491         event.getComponent().dispatchEvent(event);
492     }
493 
494     /**
495      * sends an event request to a Url, making the result of the event trigger
496      * available as a Future result that can be accessed later by client code.
497      * 
498      * @param url the url to make a request on
499      * @param payload the object that is the payload of the event
500      * @param messageProperties any properties to be associated with the payload. as
501      *            null
502      * @return the result message if any of the invocation
503      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
504      *             transfromers cannot be found
505      */
506     public FutureMessageResult sendAsync(final String url, final Object payload, final Map messageProperties)
507         throws UMOException
508     {
509         return sendAsync(url, payload, messageProperties, 0);
510     }
511 
512     /**
513      * sends an event request to a Url, making the result of the event trigger
514      * available as a Future result that can be accessed later by client code.
515      * 
516      * @param url the url to make a request on
517      * @param message the message to send
518      * @return the result message if any of the invocation
519      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
520      *             transfromers cannot be found
521      */
522     public FutureMessageResult sendAsync(final String url, final UMOMessage message) throws UMOException
523     {
524         return sendAsync(url, message, UMOEvent.TIMEOUT_NOT_SET_VALUE);
525     }
526 
527     /**
528      * sends an event request to a Url, making the result of the event trigger
529      * available as a Future result that can be accessed later by client code.
530      * 
531      * @param url the url to make a request on
532      * @param payload the object that is the payload of the event
533      * @param messageProperties any properties to be associated with the payload. as
534      *            null
535      * @param timeout how long to block in milliseconds waiting for a result
536      * @return the result message if any of the invocation
537      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
538      *             transfromers cannot be found
539      */
540     public FutureMessageResult sendAsync(final String url,
541                                          final Object payload,
542                                          final Map messageProperties,
543                                          final int timeout) throws UMOException
544     {
545         return sendAsync(url, new MuleMessage(payload, messageProperties), timeout);
546     }
547 
548     /**
549      * sends an event request to a Url, making the result of the event trigger
550      * available as a Future result that can be accessed later by client code.
551      * 
552      * @param url the url to make a request on
553      * @param message the message to send
554      * @param timeout how long to block in milliseconds waiting for a result
555      * @return the result message if any of the invocation
556      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
557      *             transfromers cannot be found
558      */
559     public FutureMessageResult sendAsync(final String url, final UMOMessage message, final int timeout)
560         throws UMOException
561     {
562         Callable call = new Callable()
563         {
564             public Object call() throws Exception
565             {
566                 return send(url, message, timeout);
567             }
568         };
569 
570         FutureMessageResult result = new FutureMessageResult(call);
571 
572         if (asyncExecutor != null)
573         {
574             result.setExecutor(asyncExecutor);
575         }
576 
577         result.execute();
578         return result;
579     }
580 
581     /**
582      * sends an event to a components on a local Mule instance, while making the
583      * result of the event trigger available as a Future result that can be accessed
584      * later by client code. If forwardDirectRequests flag s set and the components
585      * is not found on the local Mule instance it will forward to a remote server.
586      * Users can endpoint a url to a remote Mule server in the constructor of a Mule
587      * client, by default the default Mule server url tcp://localhost:60504 is used.
588      * 
589      * @param component the name of the Mule components to send to
590      * @param transformers a comma separated list of transformers to apply to the
591      *            result message
592      * @param payload the object that is the payload of the event
593      * @param messageProperties any properties to be associated with the payload. as
594      *            null
595      * @return the result message if any of the invocation
596      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
597      *             transfromers cannot be found
598      */
599     public FutureMessageResult sendDirectAsync(final String component,
600                                                String transformers,
601                                                final Object payload,
602                                                final Map messageProperties) throws UMOException
603     {
604         return sendDirectAsync(component, transformers, new MuleMessage(payload, messageProperties));
605     }
606 
607     /**
608      * sends an event to a components on a local Mule instance, while making the
609      * result of the event trigger available as a Future result that can be accessed
610      * later by client code. If forwardDirectRequests flag s set and the components
611      * is not found on the local Mule instance it will forward to a remote server.
612      * Users can endpoint a url to a remote Mule server in the constructor of a Mule
613      * client, by default the default Mule server url tcp://localhost:60504 is used.
614      * 
615      * @param component the name of the Mule components to send to
616      * @param transformers a comma separated list of transformers to apply to the
617      *            result message
618      * @param message the message to send
619      * @return the result message if any of the invocation
620      * @throws org.mule.umo.UMOException if the dispatch fails or the components or
621      *             transfromers cannot be found
622      */
623     public FutureMessageResult sendDirectAsync(final String component,
624                                                String transformers,
625                                                final UMOMessage message) throws UMOException
626     {
627         Callable call = new Callable()
628         {
629             public Object call() throws Exception
630             {
631                 return sendDirect(component, null, message);
632             }
633         };
634 
635         FutureMessageResult result = new FutureMessageResult(call);
636 
637         if (asyncExecutor != null)
638         {
639             result.setExecutor(asyncExecutor);
640         }
641 
642         if (StringUtils.isNotBlank(transformers))
643         {
644             result.setTransformer(MuleObjectHelper.getTransformer(transformers, ","));
645         }
646 
647         result.execute();
648         return result;
649     }
650 
651     /**
652      * Sends an event synchronously to a endpointUri via a mule server and a
653      * resulting message is returned.
654      * 
655      * @param url the Mule url used to determine the destination and transport of the
656      *            message
657      * @param payload the object that is the payload of the event
658      * @param messageProperties any properties to be associated with the payload. In
659      *            the case of Jms you could set the JMSReplyTo property in these
660      *            properties.
661      * @return A return message, this could be null if the the components invoked
662      *         explicitly sets a return as null
663      * @throws org.mule.umo.UMOException
664      */
665     public UMOMessage send(String url, Object payload, Map messageProperties) throws UMOException
666     {
667         return send(url, payload, messageProperties, UMOEvent.TIMEOUT_NOT_SET_VALUE);
668     }
669 
670     /**
671      * Sends an event synchronously to a endpointUri via a mule server and a
672      * resulting message is returned.
673      * 
674      * @param url the Mule url used to determine the destination and transport of the
675      *            message
676      * @param message the Message for the event
677      * @return A return message, this could be null if the the components invoked
678      *         explicitly sets a return as null
679      * @throws org.mule.umo.UMOException
680      */
681     public UMOMessage send(String url, UMOMessage message) throws UMOException
682     {
683         return send(url, message, UMOEvent.TIMEOUT_NOT_SET_VALUE);
684     }
685 
686     /**
687      * Sends an event synchronously to a endpointUri via a mule server and a
688      * resulting message is returned.
689      * 
690      * @param url the Mule url used to determine the destination and transport of the
691      *            message
692      * @param payload the object that is the payload of the event
693      * @param messageProperties any properties to be associated with the payload. In
694      *            the case of Jms you could set the JMSReplyTo property in these
695      *            properties.
696      * @param timeout The time in milliseconds the the call should block waiting for
697      *            a response
698      * @return A return message, this could be null if the the components invoked
699      *         explicitly sets a return as null
700      * @throws org.mule.umo.UMOException
701      */
702     public UMOMessage send(String url, Object payload, Map messageProperties, int timeout)
703         throws UMOException
704     {
705         if (messageProperties == null)
706         {
707             messageProperties = new HashMap();
708         }
709         if (messageProperties.get(MuleProperties.MULE_REMOTE_SYNC_PROPERTY) == null)
710         {
711             messageProperties.put(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, "true");
712         }
713         UMOMessage message = new MuleMessage(payload, messageProperties);
714         return send(url, message, timeout);
715     }
716 
717     /**
718      * Sends an event synchronously to a endpointUri via a mule server and a
719      * resulting message is returned.
720      * 
721      * @param url the Mule url used to determine the destination and transport of the
722      *            message
723      * @param message The message to send
724      * @param timeout The time in milliseconds the the call should block waiting for
725      *            a response
726      * @return A return message, this could be null if the the components invoked
727      *         explicitly sets a return as null
728      * @throws org.mule.umo.UMOException
729      */
730     public UMOMessage send(String url, UMOMessage message, int timeout) throws UMOException
731     {
732         UMOEvent event = getEvent(message, url, true, false);
733         event.setTimeout(timeout);
734 
735         try
736         {
737             return event.getSession().sendEvent(event);
738         }
739         catch (UMOException e)
740         {
741             throw e;
742         }
743         catch (Exception e)
744         {
745             throw new DispatchException(ClientMessages.failedToDispatchClientEvent(), 
746                 event.getMessage(), event.getEndpoint(), e);
747         }
748     }
749 
750     /**
751      * Will receive an event from an endpointUri determined by the url
752      * 
753      * @param url the Mule url used to determine the destination and transport of the
754      *            message
755      * @param timeout how long to block waiting to receive the event, if set to 0 the
756      *            receive will not wait at all and if set to -1 the receive will wait
757      *            forever
758      * @return the message received or null if no message was received
759      * @throws org.mule.umo.UMOException
760      */
761     public UMOMessage receive(String url, long timeout) throws UMOException
762     {
763         UMOEndpoint endpoint = getEndpoint(url, UMOEndpoint.ENDPOINT_TYPE_RECEIVER);
764         try
765         {
766             UMOMessage message = endpoint.receive(timeout);
767             if (message != null && endpoint.getTransformer() != null)
768             {
769                 if (endpoint.getTransformer().isSourceTypeSupported(message.getPayload().getClass()))
770                 {
771                     message = new MuleMessage(endpoint.getTransformer().transform(message.getPayload()),
772                         message);
773                 }
774             }
775             return message;
776         }
777         catch (Exception e)
778         {
779             throw new ReceiveException(endpoint, timeout, e);
780         }
781     }
782 
783     /**
784      * Will receive an event from an endpointUri determined by the url
785      * 
786      * @param url the Mule url used to determine the destination and transport of the
787      *            message
788      * @param transformers A comma separated list of transformers used to apply to
789      *            the result message
790      * @param timeout how long to block waiting to receive the event, if set to 0 the
791      *            receive will not wait at all and if set to -1 the receive will wait
792      *            forever
793      * @return the message received or null if no message was received
794      * @throws org.mule.umo.UMOException
795      */
796     public UMOMessage receive(String url, String transformers, long timeout) throws UMOException
797     {
798         return receive(url, MuleObjectHelper.getTransformer(transformers, ","), timeout);
799     }
800 
801     /**
802      * Will receive an event from an endpointUri determined by the url
803      * 
804      * @param url the Mule url used to determine the destination and transport of the
805      *            message
806      * @param transformer A transformer used to apply to the result message
807      * @param timeout how long to block waiting to receive the event, if set to 0 the
808      *            receive will not wait at all and if set to -1 the receive will wait
809      *            forever
810      * @return the message received or null if no message was received
811      * @throws org.mule.umo.UMOException
812      */
813     public UMOMessage receive(String url, UMOTransformer transformer, long timeout) throws UMOException
814     {
815         UMOMessage message = receive(url, timeout);
816         if (message != null && transformer != null)
817         {
818             return new MuleMessage(transformer.transform(message.getPayload()));
819         }
820         else
821         {
822             return message;
823         }
824     }
825 
826     /**
827      * Packages a mule event for the current request
828      * 
829      * @param message the event payload
830      * @param uri the destination endpointUri
831      * @param synchronous whether the event will be synchronously processed
832      * @param streaming
833      * @return the UMOEvent
834      * @throws UMOException
835      */
836     protected UMOEvent getEvent(UMOMessage message, String uri, boolean synchronous, boolean streaming)
837         throws UMOException
838     {
839         UMOEndpoint endpoint = getEndpoint(uri, UMOEndpoint.ENDPOINT_TYPE_SENDER);
840         if (!endpoint.getConnector().isStarted() && manager.isStarted())
841         {
842             endpoint.getConnector().startConnector();
843         }
844         endpoint.setStreaming(streaming);
845         try
846         {
847             MuleSession session = new MuleSession(message,
848                 ((AbstractConnector)endpoint.getConnector()).getSessionHandler());
849 
850             if (user != null)
851             {
852                 message.setProperty(MuleProperties.MULE_USER_PROPERTY, MuleCredentials.createHeader(
853                     user.getUsername(), user.getPassword()));
854             }
855             MuleEvent event = new MuleEvent(message, endpoint, session, synchronous);
856             return event;
857         }
858         catch (Exception e)
859         {
860             throw new DispatchException(CoreMessages.failedToCreate("Client event"), message, endpoint, e);
861         }
862     }
863 
864     protected UMOEndpoint getEndpoint(String uri, String type) throws UMOException
865     {
866         UMOEndpoint endpoint = manager.lookupEndpoint(uri);
867         if (endpoint == null)
868         {
869             endpoint = MuleEndpoint.getOrCreateEndpointForUri(uri, type);
870         }
871         return endpoint;
872     }
873 
874     protected UMOEndpoint getDefaultClientEndpoint(UMODescriptor descriptor, Object payload)
875         throws UMOException
876     {
877         // as we are bypassing the message transport layer we need to check that
878         UMOEndpoint endpoint = descriptor.getInboundEndpoint();
879         if (endpoint != null)
880         {
881             if (endpoint.getTransformer() != null)
882             {
883                 if (endpoint.getTransformer().isSourceTypeSupported(payload.getClass()))
884                 {
885                     return endpoint;
886                 }
887                 else
888                 {
889                     endpoint = new MuleEndpoint(endpoint);
890                     endpoint.setTransformer(null);
891                     return endpoint;
892                 }
893             }
894             else
895             {
896                 return endpoint;
897             }
898         }
899         else
900         {
901             UMOConnector connector = null;
902             UMOEndpointURI defaultEndpointUri = new MuleEndpointURI("vm://mule.client");
903             connector = TransportFactory.createConnector(defaultEndpointUri);
904             manager.registerConnector(connector);
905             connector.startConnector();
906             endpoint = new MuleEndpoint("muleClientProvider", defaultEndpointUri, connector, null,
907                 UMOEndpoint.ENDPOINT_TYPE_RECEIVER, 0, null, null);
908         }
909 
910         manager.registerEndpoint(endpoint);
911         return endpoint;
912     }
913 
914     /**
915      * Sends an event synchronously to a endpointUri via a mule server without
916      * waiting for the result.
917      * 
918      * @param url the Mule url used to determine the destination and transport of the
919      *            message
920      * @param payload the object that is the payload of the event
921      * @param messageProperties any properties to be associated with the payload. In
922      *            the case of Jms you could set the JMSReplyTo property in these
923      *            properties.
924      * @throws org.mule.umo.UMOException
925      */
926     public void sendNoReceive(String url, Object payload, Map messageProperties) throws UMOException
927     {
928         if (messageProperties == null)
929         {
930             messageProperties = new HashMap();
931         }
932         messageProperties.put(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, "false");
933         UMOMessage message = new MuleMessage(payload, messageProperties);
934         UMOEvent event = getEvent(message, url, true, false);
935         try
936         {
937             event.getSession().sendEvent(event);
938         }
939         catch (UMOException e)
940         {
941             throw e;
942         }
943         catch (Exception e)
944         {
945             throw new DispatchException(ClientMessages.failedToDispatchClientEvent(), 
946                 event.getMessage(), event.getEndpoint(), e);
947         }
948     }
949 
950     /**
951      * Overriding methods may want to return a custom manager here
952      * 
953      * @return the UMOManager to use
954      */
955     public UMOManager getManager()
956     {
957         return MuleManager.getInstance();
958     }
959 
960     /**
961      * Registers a java object as a Umo pcomponent that listens for events on the
962      * given url. By default the ThreadingProfile for the components will be set so
963      * that there will only be one thread of execution.
964      * 
965      * @param component any java object, Mule will it's endpointUri discovery to
966      *            determine which event to invoke based on the evnet payload type
967      * @param name The identifying name of the components. This can be used to later
968      *            unregister it
969      * @param listenerEndpoint The url endpointUri to listen to
970      * @throws UMOException
971      */
972     public void registerComponent(Object component, String name, UMOEndpointURI listenerEndpoint)
973         throws UMOException
974     {
975         builder.registerComponentInstance(component, name, listenerEndpoint, null);
976     }
977 
978     /**
979      * Registers a java object as a Umo pcomponent that listens for and sends events
980      * on the given urls. By default the ThreadingProfile for the components will be
981      * set so that there will only be one thread of execution.
982      * 
983      * @param component any java object, Mule will it's endpointUri discovery to
984      *            determine which event to invoke based on the evnet payload type
985      * @param name The identifying name of the components. This can be used to later
986      *            unregister it
987      * @param listenerEndpoint The url endpointUri to listen to
988      * @param sendEndpoint The url endpointUri to dispatch to
989      * @throws UMOException
990      */
991     public void registerComponent(Object component,
992                                   String name,
993                                   MuleEndpointURI listenerEndpoint,
994                                   MuleEndpointURI sendEndpoint) throws UMOException
995     {
996         builder.registerComponentInstance(component, name, listenerEndpoint, sendEndpoint);
997     }
998 
999     /**
1000      * Registers a user configured MuleDescriptor of a components to the server. If
1001      * users want to register object instances with the server rather than class
1002      * names that get created at runtime or reference to objects in the container,
1003      * the user must call the descriptors setImplementationInstance() method - <code>
1004      * MyBean implementation = new MyBean();
1005      * descriptor.setImplementationInstance(implementation);
1006      * </code>
1007      * Calling this method is equivilent to calling UMOModel.registerComponent(..)
1008      * 
1009      * @param descriptor the componet descriptor to register
1010      * @throws UMOException the descriptor is invalid or cannot be initialised or
1011      *             started
1012      * @see org.mule.umo.model.UMOModel
1013      */
1014     public void registerComponent(UMODescriptor descriptor) throws UMOException
1015     {
1016         builder.registerComponent(descriptor);
1017     }
1018 
1019     /**
1020      * Unregisters a previously register components. This will also unregister any
1021      * listeners for the components Calling this method is equivilent to calling
1022      * UMOModel.unregisterComponent(..)
1023      * 
1024      * @param name the name of the componet to unregister
1025      * @throws UMOException if unregistering the components fails, i.e. The
1026      *             underlying transport fails to unregister a listener. If the
1027      *             components does not exist, this method should not throw an
1028      *             exception.
1029      * @see org.mule.umo.model.UMOModel
1030      */
1031     public void unregisterComponent(String name) throws UMOException
1032     {
1033         builder.unregisterComponent(name);
1034     }
1035 
1036     public RemoteDispatcher getRemoteDispatcher(String serverEndpoint) throws UMOException
1037     {
1038         RemoteDispatcher rd = new RemoteDispatcher(serverEndpoint);
1039         rd.setExecutor(asyncExecutor);
1040         dispatchers.add(rd);
1041         return rd;
1042     }
1043 
1044     public RemoteDispatcher getRemoteDispatcher(String serverEndpoint, String user, String password)
1045         throws UMOException
1046     {
1047         RemoteDispatcher rd = new RemoteDispatcher(serverEndpoint, new MuleCredentials(user,
1048             password.toCharArray()));
1049         rd.setExecutor(asyncExecutor);
1050         dispatchers.add(rd);
1051         return rd;
1052     }
1053 
1054     /**
1055      * Will dispose the MuleManager instance *IF* a new instance was created for this
1056      * client. Otherwise this method only cleans up resources no longer needed
1057      */
1058     public void dispose()
1059     {
1060         synchronized (dispatchers)
1061         {
1062             for (Iterator iterator = dispatchers.iterator(); iterator.hasNext();)
1063             {
1064                 RemoteDispatcher remoteDispatcher = (RemoteDispatcher)iterator.next();
1065                 remoteDispatcher.dispose();
1066                 remoteDispatcher = null;
1067             }
1068             dispatchers.clear();
1069         }
1070         // Dispose the manager only if the manager was created for this client
1071         if (MuleManager.getConfiguration().isClientMode())
1072         {
1073             manager.dispose();
1074         }
1075     }
1076 
1077     public void setProperty(Object key, Object value)
1078     {
1079         manager.setProperty(key, value);
1080     }
1081 
1082     public Object getProperty(Object key)
1083     {
1084         return manager.getProperty(key);
1085     }
1086 
1087     public MuleConfiguration getConfiguration()
1088     {
1089         return MuleManager.getConfiguration();
1090     }
1091 }