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