View Javadoc

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