Coverage Report - org.mule.transport.AbstractConnector
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractConnector
0%
0/588
0%
0/250
0
AbstractConnector$1
0%
0/17
0%
0/6
0
AbstractConnector$2
0%
0/9
0%
0/2
0
AbstractConnector$3
0%
0/18
0%
0/8
0
AbstractConnector$4
0%
0/4
N/A
0
AbstractConnector$5
0%
0/12
0%
0/8
0
AbstractConnector$6
0%
0/5
N/A
0
AbstractConnector$7
0%
0/5
N/A
0
AbstractConnector$8
0%
0/2
N/A
0
AbstractConnector$DispatcherMessageProcessor
0%
0/15
0%
0/2
0
 
 1  
 /*
 2  
  * $Id: AbstractConnector.java 20531 2010-12-08 21:34:21Z dzapata $
 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.transport;
 12  
 
 13  
 import org.mule.MessageExchangePattern;
 14  
 import org.mule.api.MuleContext;
 15  
 import org.mule.api.MuleEvent;
 16  
 import org.mule.api.MuleException;
 17  
 import org.mule.api.MuleMessage;
 18  
 import org.mule.api.MuleRuntimeException;
 19  
 import org.mule.api.config.MuleProperties;
 20  
 import org.mule.api.config.ThreadingProfile;
 21  
 import org.mule.api.construct.FlowConstruct;
 22  
 import org.mule.api.context.WorkManager;
 23  
 import org.mule.api.context.WorkManagerSource;
 24  
 import org.mule.api.context.notification.ServerNotification;
 25  
 import org.mule.api.context.notification.ServerNotificationHandler;
 26  
 import org.mule.api.endpoint.EndpointURI;
 27  
 import org.mule.api.endpoint.ImmutableEndpoint;
 28  
 import org.mule.api.endpoint.InboundEndpoint;
 29  
 import org.mule.api.endpoint.OutboundEndpoint;
 30  
 import org.mule.api.lifecycle.CreateException;
 31  
 import org.mule.api.lifecycle.InitialisationException;
 32  
 import org.mule.api.lifecycle.LifecycleCallback;
 33  
 import org.mule.api.lifecycle.LifecycleException;
 34  
 import org.mule.api.lifecycle.LifecycleState;
 35  
 import org.mule.api.processor.MessageProcessor;
 36  
 import org.mule.api.registry.ServiceException;
 37  
 import org.mule.api.registry.ServiceType;
 38  
 import org.mule.api.retry.RetryCallback;
 39  
 import org.mule.api.retry.RetryContext;
 40  
 import org.mule.api.retry.RetryPolicyTemplate;
 41  
 import org.mule.api.transformer.Transformer;
 42  
 import org.mule.api.transport.Connectable;
 43  
 import org.mule.api.transport.Connector;
 44  
 import org.mule.api.transport.ConnectorException;
 45  
 import org.mule.api.transport.DispatchException;
 46  
 import org.mule.api.transport.MessageDispatcher;
 47  
 import org.mule.api.transport.MessageDispatcherFactory;
 48  
 import org.mule.api.transport.MessageReceiver;
 49  
 import org.mule.api.transport.MessageRequester;
 50  
 import org.mule.api.transport.MessageRequesterFactory;
 51  
 import org.mule.api.transport.MuleMessageFactory;
 52  
 import org.mule.api.transport.ReplyToHandler;
 53  
 import org.mule.api.transport.SessionHandler;
 54  
 import org.mule.config.i18n.CoreMessages;
 55  
 import org.mule.config.i18n.MessageFactory;
 56  
 import org.mule.context.notification.ConnectionNotification;
 57  
 import org.mule.context.notification.EndpointMessageNotification;
 58  
 import org.mule.context.notification.OptimisedNotificationHandler;
 59  
 import org.mule.endpoint.outbound.OutboundNotificationMessageProcessor;
 60  
 import org.mule.model.streaming.DelegatingInputStream;
 61  
 import org.mule.processor.OptionalAsyncInterceptingMessageProcessor;
 62  
 import org.mule.processor.chain.DefaultMessageProcessorChainBuilder;
 63  
 import org.mule.routing.filters.WildcardFilter;
 64  
 import org.mule.session.SerializeAndEncodeSessionHandler;
 65  
 import org.mule.transformer.TransformerUtils;
 66  
 import org.mule.transport.service.TransportFactory;
 67  
 import org.mule.transport.service.TransportServiceDescriptor;
 68  
 import org.mule.transport.service.TransportServiceException;
 69  
 import org.mule.util.ClassUtils;
 70  
 import org.mule.util.CollectionUtils;
 71  
 import org.mule.util.ObjectNameHelper;
 72  
 import org.mule.util.ObjectUtils;
 73  
 import org.mule.util.StringUtils;
 74  
 import org.mule.util.concurrent.NamedThreadFactory;
 75  
 import org.mule.util.concurrent.ThreadNameHelper;
 76  
 
 77  
 import java.io.IOException;
 78  
 import java.io.InputStream;
 79  
 import java.io.OutputStream;
 80  
 import java.text.MessageFormat;
 81  
 import java.util.ArrayList;
 82  
 import java.util.Collections;
 83  
 import java.util.Iterator;
 84  
 import java.util.List;
 85  
 import java.util.Map;
 86  
 import java.util.Properties;
 87  
 
 88  
 import javax.resource.spi.work.WorkEvent;
 89  
 import javax.resource.spi.work.WorkListener;
 90  
 
 91  
 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
 92  
 import edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService;
 93  
 import edu.emory.mathcs.backport.java.util.concurrent.ScheduledThreadPoolExecutor;
 94  
 import edu.emory.mathcs.backport.java.util.concurrent.ThreadFactory;
 95  
 import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
 96  
 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
 97  
 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicReference;
 98  
 import org.apache.commons.logging.Log;
 99  
 import org.apache.commons.logging.LogFactory;
 100  
 import org.apache.commons.pool.KeyedPoolableObjectFactory;
 101  
 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
 102  
 
 103  
 /**
 104  
  * <code>AbstractConnector</code> provides base functionality for all connectors
 105  
  * provided with Mule. Connectors are the mechanism used to connect to external
 106  
  * systems and protocols in order to send and receive data.
 107  
  * <p/>
 108  
  * The <code>AbstractConnector</code> provides getter and setter methods for endpoint
 109  
  * name, transport name and protocol. It also provides methods to stop and start
 110  
  * connectors and sets up a dispatcher threadpool which allows deriving connectors
 111  
  * the possibility to dispatch work to separate threads. This functionality is
 112  
  * controlled with the <i> doThreading</i> property on the threadingProfiles for
 113  
  * dispatchers and receivers. The lifecycle for a connector is -
 114  
  * <ol>
 115  
  * <li>Create
 116  
  * <li>Initialise
 117  
  * <li>Connect
 118  
  * <li>Connect receivers
 119  
  * <li>Start
 120  
  * <li>Start Receivers
 121  
  * <li>Stop
 122  
  * <li>Stop Receivers
 123  
  * <li>Disconnect
 124  
  * <li>Disconnect Receivers
 125  
  * <li>Dispose
 126  
  * <li>Dispose Receivers
 127  
  * </ol>
 128  
  */
 129  0
 public abstract class AbstractConnector implements Connector, WorkListener
 130  
 {
 131  
     /**
 132  
      * Default number of concurrent transactional receivers.
 133  
      */
 134  
     public static final int DEFAULT_NUM_CONCURRENT_TX_RECEIVERS = 4;
 135  
 
 136  
     private static final long SCHEDULER_FORCED_SHUTDOWN_TIMEOUT = 5000l;
 137  
     
 138  
     public static final String PROPERTY_POLLING_FREQUENCY = "pollingFrequency";
 139  
 
 140  
     /**
 141  
      * logger used by this class
 142  
      */
 143  0
     protected final Log logger = LogFactory.getLog(getClass());
 144  
 
 145  
     /**
 146  
      * The name that identifies the endpoint
 147  
      */
 148  
     protected volatile String name;
 149  
 
 150  
     /**
 151  
      * Factory used to create dispatchers for this connector
 152  
      */
 153  
     protected volatile MessageDispatcherFactory dispatcherFactory;
 154  
 
 155  
     /**
 156  
      * Factory used to create requesters for this connector
 157  
      */
 158  
     protected volatile MessageRequesterFactory requesterFactory;
 159  
 
 160  
     /**
 161  
      * Factory used to create new {@link MuleMessage} instances
 162  
      */
 163  
     protected MuleMessageFactory muleMessageFactory;
 164  
 
 165  
     /**
 166  
      * A pool of dispatchers for this connector, keyed by endpoint
 167  
      */
 168  
     protected volatile ConfigurableKeyedObjectPool dispatchers;
 169  
 
 170  
     /**
 171  
      * A factory for creating the pool of dispatchers for this connector.
 172  
      */
 173  
     protected volatile ConfigurableKeyedObjectPoolFactory dispatcherPoolFactory;
 174  
 
 175  
     /**
 176  
      * A pool of requesters for this connector, keyed by endpoint
 177  
      */
 178  0
     protected final GenericKeyedObjectPool requesters = new GenericKeyedObjectPool();
 179  
 
 180  
     /**
 181  
      * The collection of listeners on this connector. Keyed by entrypoint
 182  
      */
 183  0
     @SuppressWarnings("unchecked")
 184  
     protected final Map<Object, MessageReceiver> receivers = new ConcurrentHashMap/* <Object, MessageReceiver> */();
 185  
 
 186  
     /**
 187  
      * Defines the dispatcher threading profile
 188  
      */
 189  
     private volatile ThreadingProfile dispatcherThreadingProfile;
 190  
 
 191  
     /**
 192  
      * Defines the requester threading profile
 193  
      */
 194  
     private volatile ThreadingProfile requesterThreadingProfile;
 195  
 
 196  
     /**
 197  
      * Defines the receiver threading profile
 198  
      */
 199  
     private volatile ThreadingProfile receiverThreadingProfile;
 200  
 
 201  
     /**
 202  
      * @see #isCreateMultipleTransactedReceivers()
 203  
      */
 204  0
     protected volatile boolean createMultipleTransactedReceivers = true;
 205  
 
 206  
     /**
 207  
      * @see #getNumberOfConcurrentTransactedReceivers()
 208  
      */
 209  0
     protected volatile int numberOfConcurrentTransactedReceivers = DEFAULT_NUM_CONCURRENT_TX_RECEIVERS;
 210  
 
 211  
     private RetryPolicyTemplate retryPolicyTemplate;
 212  
 
 213  
     /**
 214  
      * Optimise the handling of message notifications. If dynamic is set to false
 215  
      * then the cached notification handler implements a shortcut for message
 216  
      * notifications.
 217  
      */
 218  0
     private boolean dynamicNotification = false;
 219  
     private ServerNotificationHandler cachedNotificationHandler;
 220  
 
 221  
     private final List<String> supportedProtocols;
 222  
 
 223  
     /**
 224  
      * A shared work manager for all receivers registered with this connector.
 225  
      */
 226  0
     private final AtomicReference/* <WorkManager> */receiverWorkManager = new AtomicReference();
 227  
 
 228  
     /**
 229  
      * A shared work manager for all requesters created for this connector.
 230  
      */
 231  0
     private final AtomicReference/* <WorkManager> */dispatcherWorkManager = new AtomicReference();
 232  
 
 233  
     /**
 234  
      * A shared work manager for all requesters created for this connector.
 235  
      */
 236  0
     private final AtomicReference/* <WorkManager> */requesterWorkManager = new AtomicReference();
 237  
 
 238  
     /**
 239  
      * A generic scheduling service for tasks that need to be performed periodically.
 240  
      */
 241  
     private ScheduledExecutorService scheduler;
 242  
 
 243  
     /**
 244  
      * Holds the service configuration for this connector
 245  
      */
 246  
     protected volatile TransportServiceDescriptor serviceDescriptor;
 247  
 
 248  
     /**
 249  
      * The map of service overrides that can be used to extend the capabilities of
 250  
      * the connector
 251  
      */
 252  
     protected volatile Properties serviceOverrides;
 253  
 
 254  
     /**
 255  
      * The strategy used for reading and writing session information to and from the
 256  
      * transport
 257  
      */
 258  0
     protected volatile SessionHandler sessionHandler = new SerializeAndEncodeSessionHandler();
 259  
 
 260  
     protected MuleContext muleContext;
 261  
 
 262  
     protected ConnectorLifecycleManager lifecycleManager;
 263  
 
 264  
     // TODO connect and disconnect are not part of lifecycle management right now
 265  0
     protected AtomicBoolean connected = new AtomicBoolean(false);
 266  
 
 267  
     /**
 268  
      * Indicates whether the connector should start upon connecting. This is
 269  
      * necessary to support asynchronous retry policies, otherwise the start() method
 270  
      * would block until connection is successful.
 271  
      */
 272  0
     protected boolean startOnConnect = false;
 273  
 
 274  
     /**
 275  
      * The will cause the connector not to start when {@link #start()} is called. The
 276  
      * only way to start the connector is to call
 277  
      * {@link #setInitialStateStopped(boolean)} with 'false' and then calling
 278  
      * {@link #start()}. This flag is used internally since some connectors that rely
 279  
      * on external servers may need to wait for that server to become available
 280  
      * before starting
 281  
      */
 282  0
     protected boolean initialStateStopped = false;
 283  
     /**
 284  
      * Whether to test a connection on each take.
 285  
      */
 286  0
     private boolean validateConnections = true;
 287  
 
 288  
     public AbstractConnector(MuleContext context)
 289  0
     {
 290  0
         muleContext = context;
 291  0
         lifecycleManager = new ConnectorLifecycleManager(this);
 292  
 
 293  0
         setDynamicNotification(false);
 294  0
         updateCachedNotificationHandler();
 295  
 
 296  
         // always add at least the default protocol
 297  0
         supportedProtocols = new ArrayList<String>();
 298  0
         supportedProtocols.add(getProtocol().toLowerCase());
 299  
 
 300  
         // TODO dispatcher pool configuration should be extracted, maybe even
 301  
         // moved into the factory?
 302  
         // NOTE: testOnBorrow MUST be FALSE. this is a bit of a design bug in
 303  
         // commons-pool since validate is used for both activation and passivation,
 304  
         // but has no way of knowing which way it is going.
 305  0
         requesters.setTestOnBorrow(false);
 306  0
         requesters.setTestOnReturn(true);
 307  0
     }
 308  
 
 309  
     public String getName()
 310  
     {
 311  0
         return name;
 312  
     }
 313  
 
 314  
     public void setName(String newName)
 315  
     {
 316  0
         if (newName == null)
 317  
         {
 318  0
             throw new IllegalArgumentException(CoreMessages.objectIsNull("Connector name").toString());
 319  
         }
 320  
 
 321  0
         if (logger.isDebugEnabled())
 322  
         {
 323  0
             logger.debug("Set Connector name to: " + newName);
 324  
         }
 325  
 
 326  0
         name = newName;
 327  0
     }
 328  
 
 329  
     //-----------------------------------------------------------------------------------------------//
 330  
     //-             LIFECYCLE METHODS
 331  
     //-----------------------------------------------------------------------------------------------//
 332  
 
 333  
     ConnectorLifecycleManager getLifecycleManager()
 334  
     {
 335  0
         return lifecycleManager;
 336  
     }
 337  
 
 338  
     public LifecycleState getLifecycleState()
 339  
     {
 340  0
         return lifecycleManager.getState();
 341  
     }
 342  
 
 343  
     public final synchronized void initialise() throws InitialisationException
 344  
     {
 345  
         try
 346  
         {
 347  0
             lifecycleManager.fireInitialisePhase(new LifecycleCallback<Connector>()
 348  0
             {
 349  
                 public void onTransition(String phaseName, Connector object) throws MuleException
 350  
                 {
 351  0
                     if (retryPolicyTemplate == null)
 352  
                     {
 353  0
                         retryPolicyTemplate = (RetryPolicyTemplate) muleContext.getRegistry().lookupObject(
 354  
                                 MuleProperties.OBJECT_DEFAULT_RETRY_POLICY_TEMPLATE);
 355  
                     }
 356  
 
 357  0
                     if (dispatcherPoolFactory == null) {
 358  0
                         dispatcherPoolFactory = new DefaultConfigurableKeyedObjectPoolFactory();
 359  
                     }
 360  
 
 361  0
                     dispatchers = dispatcherPoolFactory.createObjectPool();
 362  0
                     if (dispatcherFactory != null) {
 363  0
                         dispatchers.setFactory(getWrappedDispatcherFactory(dispatcherFactory));
 364  
                     }
 365  
 
 366  
                     // Initialise the structure of this connector
 367  0
                     initFromServiceDescriptor();
 368  
 
 369  0
                     configureDispatcherPool();
 370  0
                     setMaxRequestersActive(getRequesterThreadingProfile().getMaxThreadsActive());
 371  
 
 372  0
                     doInitialise();
 373  
 
 374  
                     try
 375  
                     {
 376  0
                         initWorkManagers();
 377  
                     }
 378  0
                     catch (MuleException e)
 379  
                     {
 380  0
                         throw new LifecycleException(e, this);
 381  0
                     }
 382  0
                 }
 383  
             });
 384  
         }
 385  0
         catch (InitialisationException e)
 386  
         {
 387  0
             throw e;
 388  
         }
 389  0
         catch (LifecycleException e)
 390  
         {
 391  0
             throw new InitialisationException(e, this);
 392  
         }
 393  0
         catch (MuleException e)
 394  
         {
 395  0
             e.printStackTrace();
 396  0
         }
 397  0
     }
 398  
 
 399  
     public final synchronized void start() throws MuleException
 400  
     {
 401  0
         if (isInitialStateStopped())
 402  
         {
 403  0
             logger.info("Connector not started because 'initialStateStopped' is true");
 404  0
             return;
 405  
         }
 406  
 
 407  0
         lifecycleManager.fireStartPhase(new LifecycleCallback<Connector>()
 408  0
         {
 409  
             public void onTransition(String phaseName, Connector object) throws MuleException
 410  
             {
 411  
 
 412  
 
 413  0
                 if (!isConnected())
 414  
                 {
 415  0
                     startOnConnect = true;
 416  
 
 417  
                     // Make sure we are connected
 418  
                     try
 419  
                     {
 420  0
                         connect();
 421  
                     }
 422  0
                     catch (Exception e)
 423  
                     {
 424  0
                         throw new LifecycleException(e, this);
 425  0
                     }
 426  
                 }
 427  
                 else
 428  
                 {
 429  
                     //Do start called in this method
 430  0
                     startAfterConnect();
 431  
                 }
 432  0
             }
 433  
         });
 434  
 
 435  0
     }
 436  
 
 437  
     protected synchronized void startAfterConnect() throws MuleException
 438  
     {
 439  0
         if (logger.isInfoEnabled())
 440  
         {
 441  0
             logger.info("Starting: " + this);
 442  
         }
 443  
 
 444  
         // the scheduler is recreated after stop()
 445  0
         scheduler = createScheduler();
 446  
 
 447  
         try
 448  
         {
 449  0
             initWorkManagers();
 450  
         }
 451  0
         catch (MuleException e)
 452  
         {
 453  0
             throw new InitialisationException(e, this);
 454  0
         }
 455  
 
 456  0
         if (!isStarted())
 457  
         {
 458  0
             doStart();
 459  
         }
 460  
 
 461  0
         if (receivers != null)
 462  
         {
 463  0
             for (MessageReceiver receiver : receivers.values())
 464  
             {
 465  0
                 final List<MuleException> errors = new ArrayList<MuleException>();
 466  
                 try
 467  
                 {
 468  0
                     if (logger.isDebugEnabled())
 469  
                     {
 470  0
                         logger.debug("Starting receiver on endpoint: "
 471  
                                 + receiver.getEndpoint().getEndpointURI());
 472  
                     }
 473  0
                     if (receiver.getFlowConstruct().getLifecycleState().isStarted())
 474  
                     {
 475  0
                         receiver.start();
 476  
                     }
 477  
                 }
 478  0
                 catch (MuleException e)
 479  
                 {
 480  0
                     logger.error(e);
 481  0
                     errors.add(e);
 482  0
                 }
 483  
 
 484  0
                 if (!errors.isEmpty())
 485  
                 {
 486  
                     // throw the first one in order not to break the reconnection
 487  
                     // strategy logic,
 488  
                     // every exception has been logged above already
 489  
                     // api needs refactoring to support the multi-cause exception
 490  
                     // here
 491  0
                     throw errors.get(0);
 492  
                 }
 493  0
             }
 494  
         }
 495  
 
 496  0
     }
 497  
 
 498  
 
 499  
     public final synchronized void stop() throws MuleException
 500  
     {
 501  0
         lifecycleManager.fireStopPhase(new LifecycleCallback<Connector>()
 502  0
         {
 503  
             public void onTransition(String phaseName, Connector object) throws MuleException
 504  
             {
 505  
                  // shutdown our scheduler service
 506  0
                 shutdownScheduler();
 507  
 
 508  0
                 doStop();
 509  
 
 510  
                 // Stop all the receivers on this connector (this will cause them to
 511  
                 // disconnect too)
 512  0
                 if (receivers != null)
 513  
                 {
 514  0
                     for (MessageReceiver receiver : receivers.values())
 515  
                     {
 516  0
                         if (logger.isDebugEnabled())
 517  
                         {
 518  0
                             logger.debug("Stopping receiver on endpoint: " + receiver.getEndpoint().getEndpointURI());
 519  
                         }
 520  0
                         receiver.stop();
 521  
                     }
 522  
                 }
 523  
 
 524  0
                 if (isConnected())
 525  
                 {
 526  
                     try
 527  
                     {
 528  0
                         disconnect();
 529  
                     }
 530  0
                     catch (Exception e)
 531  
                     {
 532  
                         //TODO We only log here since we need to make sure we stop with
 533  
                         //a consistent state. Another option would be to collect exceptions
 534  
                         //and handle them at the end of this message
 535  0
                         logger.error("Failed to disconnect: " + e.getMessage(), e);
 536  0
                     }
 537  
                 }
 538  
 
 539  
                 // Now that dispatchers are borrowed/returned in worker thread we need to
 540  
                 // dispose workManager before clearing object pools
 541  0
                 disposeWorkManagers();
 542  
 
 543  
                 // Workaround for MULE-4553
 544  0
                 clearDispatchers();
 545  0
                 clearRequesters();
 546  
 
 547  
                 // make sure the scheduler is gone
 548  0
                 scheduler = null;
 549  0
             }
 550  
         });
 551  0
     }
 552  
 
 553  
     public final synchronized void dispose()
 554  
     {
 555  
         try
 556  
         {
 557  0
             if (lifecycleManager.getState().isStarted())
 558  
             {
 559  0
                 stop();
 560  
             }
 561  0
             lifecycleManager.fireDisposePhase(new LifecycleCallback<Connector>()
 562  0
             {
 563  
                 public void onTransition(String phaseName, Connector object) throws MuleException
 564  
                 {
 565  0
                     doDispose();
 566  0
                     disposeReceivers();
 567  0
                 }
 568  
             });
 569  
         }
 570  0
         catch (MuleException e)
 571  
         {
 572  0
             logger.warn("Failed to dispose connector: " + name, e);
 573  0
         }
 574  0
     }
 575  
 
 576  
     public final boolean isStarted()
 577  
     {
 578  0
         return lifecycleManager.getState().isStarted();
 579  
     }
 580  
 
 581  
     public boolean isInitialised()
 582  
     {
 583  0
         return lifecycleManager.getState().isInitialised();
 584  
     }
 585  
 
 586  
     public boolean isStopped()
 587  
     {
 588  0
         return lifecycleManager.getState().isStopped();
 589  
     }
 590  
 
 591  
 
 592  
     //-----------------------------------------------------------------------------------------------//
 593  
     //-             END LIFECYCLE METHODS
 594  
     //-----------------------------------------------------------------------------------------------//
 595  
 
 596  
    protected void configureDispatcherPool()
 597  
    {
 598  
        // Normally having a the same maximum number of dispatcher objects as threads
 599  
        // is ok.
 600  0
        int maxDispatchersActive = getDispatcherThreadingProfile().getMaxThreadsActive();
 601  
 
 602  
        // BUT if the WHEN_EXHAUSTED_RUN threading profile exhausted action is
 603  
        // configured then a single
 604  
        // additional dispatcher is required that can be used by the caller thread
 605  
        // when it executes job's itself.
 606  
        // Also See: MULE-4752
 607  0
        if (ThreadingProfile.WHEN_EXHAUSTED_RUN == getDispatcherThreadingProfile().getPoolExhaustedAction())
 608  
        {
 609  0
            maxDispatchersActive++;
 610  
        }
 611  0
        setMaxDispatchersActive(maxDispatchersActive);
 612  0
    }
 613  
 
 614  
     /**
 615  
      * <p>
 616  
      * Create a {@link MuleMessageFactory} from this connector's configuration,
 617  
      * typically through the transport descriptor.
 618  
      * </p>
 619  
      * <p/>
 620  
      * <b>Attention!</b> This method is not meant to be used by client code directly.
 621  
      * It is only publicly available to service message receivers which should be
 622  
      * used as <em>real</em> factories to create {@link MuleMessage} instances.
 623  
      *
 624  
      * @see MessageReceiver#createMuleMessage(Object)
 625  
      * @see MessageReceiver#createMuleMessage(Object, String)
 626  
      */
 627  
     public MuleMessageFactory createMuleMessageFactory() throws CreateException
 628  
     {
 629  
         try
 630  
         {
 631  0
             return serviceDescriptor.createMuleMessageFactory();
 632  
         }
 633  0
         catch (TransportServiceException tse)
 634  
         {
 635  0
             throw new CreateException(CoreMessages.failedToCreate("MuleMessageFactory"), tse, this);
 636  
         }
 637  
     }
 638  
 
 639  
     protected void shutdownScheduler()
 640  
     {
 641  0
         if (scheduler != null)
 642  
         {
 643  
             // Disable new tasks from being submitted
 644  0
             scheduler.shutdown();
 645  
             try
 646  
             {
 647  
                 // Wait a while for existing tasks to terminate
 648  0
                 if (!scheduler.awaitTermination(muleContext.getConfiguration().getShutdownTimeout(),
 649  
                         TimeUnit.MILLISECONDS))
 650  
                 {
 651  
                     // Cancel currently executing tasks and return list of pending
 652  
                     // tasks
 653  0
                     List outstanding = scheduler.shutdownNow();
 654  
                     // Wait a while for tasks to respond to being cancelled
 655  0
                     if (!scheduler.awaitTermination(SCHEDULER_FORCED_SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS))
 656  
                     {
 657  0
                         logger.warn(MessageFormat.format(
 658  
                                 "Pool {0} did not terminate in time; {1} work items were cancelled.", name,
 659  
                                 outstanding.isEmpty() ? "No" : Integer.toString(outstanding.size())));
 660  
                     }
 661  
                     else
 662  
                     {
 663  0
                         if (!outstanding.isEmpty())
 664  
                         {
 665  0
                             logger.warn(MessageFormat.format(
 666  
                                     "Pool {0} terminated; {1} work items were cancelled.", name,
 667  
                                     Integer.toString(outstanding.size())));
 668  
                         }
 669  
                     }
 670  
 
 671  
                 }
 672  
             }
 673  0
             catch (InterruptedException ie)
 674  
             {
 675  
                 // (Re-)Cancel if current thread also interrupted
 676  0
                 scheduler.shutdownNow();
 677  
                 // Preserve interrupt status
 678  0
                 Thread.currentThread().interrupt();
 679  
             }
 680  
             finally
 681  
             {
 682  0
                 scheduler = null;
 683  0
             }
 684  
         }
 685  0
     }
 686  
 
 687  
     protected void initWorkManagers() throws MuleException
 688  
     {
 689  0
         if (receiverWorkManager.get() == null)
 690  
         {
 691  
 
 692  0
             final String threadPrefix = ThreadNameHelper.receiver(muleContext, getName());
 693  0
             WorkManager newWorkManager = this.getReceiverThreadingProfile().createWorkManager(
 694  
                     threadPrefix, muleContext.getConfiguration().getShutdownTimeout());
 695  
 
 696  0
             if (receiverWorkManager.compareAndSet(null, newWorkManager))
 697  
             {
 698  0
                 newWorkManager.start();
 699  
             }
 700  
         }
 701  0
         if (dispatcherWorkManager.get() == null)
 702  
         {
 703  0
             ThreadingProfile dispatcherThreadingProfile = this.getDispatcherThreadingProfile();
 704  0
             if (dispatcherThreadingProfile.getMuleContext() == null)
 705  
             {
 706  0
                 dispatcherThreadingProfile.setMuleContext(muleContext);
 707  
             }
 708  
 
 709  0
             final String threadPrefix = ThreadNameHelper.dispatcher(muleContext, getName());
 710  0
             WorkManager newWorkManager = dispatcherThreadingProfile.createWorkManager(
 711  
                     threadPrefix, muleContext.getConfiguration().getShutdownTimeout());
 712  
 
 713  0
             if (dispatcherWorkManager.compareAndSet(null, newWorkManager))
 714  
             {
 715  0
                 newWorkManager.start();
 716  
             }
 717  
         }
 718  0
         if (requesterWorkManager.get() == null)
 719  
         {
 720  0
             final String threadPrefix = ThreadNameHelper.requester(muleContext, getName());
 721  0
             WorkManager newWorkManager = this.getRequesterThreadingProfile().createWorkManager(
 722  
                     threadPrefix, muleContext.getConfiguration().getShutdownTimeout());
 723  
 
 724  0
             if (requesterWorkManager.compareAndSet(null, newWorkManager))
 725  
             {
 726  0
                 newWorkManager.start();
 727  
             }
 728  
         }
 729  0
     }
 730  
 
 731  
     protected void disposeWorkManagers()
 732  
     {
 733  
         WorkManager workManager;
 734  
 
 735  0
         logger.debug("Disposing dispatcher work manager");
 736  0
         workManager = (WorkManager) dispatcherWorkManager.get();
 737  0
         if (workManager != null)
 738  
         {
 739  0
             workManager.dispose();
 740  
         }
 741  0
         dispatcherWorkManager.set(null);
 742  
 
 743  0
         logger.debug("Disposing requester work manager");
 744  0
         workManager = (WorkManager) requesterWorkManager.get();
 745  0
         if (workManager != null)
 746  
         {
 747  0
             workManager.dispose();
 748  
         }
 749  0
         requesterWorkManager.set(null);
 750  
 
 751  0
         logger.debug("Disposing receiver work manager");
 752  0
         workManager = (WorkManager) receiverWorkManager.get();
 753  0
         if (workManager != null)
 754  
         {
 755  0
             workManager.dispose();
 756  
         }
 757  0
         receiverWorkManager.set(null);
 758  0
     }
 759  
 
 760  
     protected void disposeReceivers()
 761  
     {
 762  0
         if (receivers != null)
 763  
         {
 764  0
             logger.debug("Disposing Receivers");
 765  
 
 766  0
             for (MessageReceiver receiver : receivers.values())
 767  
             {
 768  
                 try
 769  
                 {
 770  0
                     this.destroyReceiver(receiver, receiver.getEndpoint());
 771  
                 }
 772  0
                 catch (Throwable e)
 773  
                 {
 774  
                     // Just log when disposing
 775  0
                     logger.error("Failed to destroy receiver: " + receiver, e);
 776  0
                 }
 777  
             }
 778  
 
 779  0
             receivers.clear();
 780  0
             logger.debug("Receivers Disposed");
 781  
         }
 782  0
     }
 783  
 
 784  
     protected void clearDispatchers()
 785  
     {
 786  0
         if (dispatchers != null)
 787  
         {
 788  0
             logger.debug("Clearing Dispatcher pool");
 789  0
             synchronized (dispatchers)
 790  
             {
 791  0
                 dispatchers.clear();
 792  0
             }
 793  0
             logger.debug("Dispatcher pool cleared");
 794  
         }
 795  0
     }
 796  
 
 797  
     protected void clearRequesters()
 798  
     {
 799  0
         if (requesters != null)
 800  
         {
 801  0
             logger.debug("Clearing Requester pool");
 802  0
             requesters.clear();
 803  0
             logger.debug("Requester pool cleared");
 804  
         }
 805  0
     }
 806  
 
 807  
     public boolean isDisposed()
 808  
     {
 809  0
         return lifecycleManager.getState().isDisposed();
 810  
     }
 811  
 
 812  
     public void handleException(Exception exception)
 813  
     {
 814  0
         muleContext.getExceptionListener().handleException(exception);
 815  0
     }
 816  
 
 817  
     public void exceptionThrown(Exception e)
 818  
     {
 819  0
         handleException(e);
 820  0
     }
 821  
 
 822  
     /**
 823  
      * @return Returns the dispatcherFactory.
 824  
      */
 825  
     public MessageDispatcherFactory getDispatcherFactory()
 826  
     {
 827  0
         return dispatcherFactory;
 828  
     }
 829  
 
 830  
     /**
 831  
      * @param dispatcherFactory The dispatcherFactory to set.
 832  
      */
 833  
     public void setDispatcherFactory(MessageDispatcherFactory dispatcherFactory)
 834  
     {
 835  0
         KeyedPoolableObjectFactory poolFactory = getWrappedDispatcherFactory(dispatcherFactory);
 836  
 
 837  0
         if (dispatchers !=  null) {
 838  0
             this.dispatchers.setFactory(poolFactory);
 839  
         }
 840  
 
 841  
         // we keep a reference to the unadapted factory, otherwise people might end
 842  
         // up with ClassCastExceptions on downcast to their implementation (sigh)
 843  0
         this.dispatcherFactory = dispatcherFactory;
 844  0
     }
 845  
 
 846  
     private KeyedPoolableObjectFactory getWrappedDispatcherFactory(MessageDispatcherFactory dispatcherFactory)
 847  
     {
 848  
         KeyedPoolableObjectFactory poolFactory;
 849  0
         if (dispatcherFactory instanceof KeyedPoolableObjectFactory)
 850  
         {
 851  0
             poolFactory = (KeyedPoolableObjectFactory) dispatcherFactory;
 852  
         }
 853  
         else
 854  
         {
 855  
             // need to adapt the factory for use by commons-pool
 856  0
             poolFactory = new KeyedPoolMessageDispatcherFactoryAdapter(dispatcherFactory);
 857  
         }
 858  
 
 859  0
         return poolFactory;
 860  
     }
 861  
 
 862  
     /**
 863  
      * @return Returns the requesterFactory.
 864  
      */
 865  
     public MessageRequesterFactory getRequesterFactory()
 866  
     {
 867  0
         return requesterFactory;
 868  
     }
 869  
 
 870  
     /**
 871  
      * @param requesterFactory The requesterFactory to set.
 872  
      */
 873  
     public void setRequesterFactory(MessageRequesterFactory requesterFactory)
 874  
     {
 875  
         KeyedPoolableObjectFactory poolFactory;
 876  
 
 877  0
         if (requesterFactory instanceof KeyedPoolableObjectFactory)
 878  
         {
 879  0
             poolFactory = (KeyedPoolableObjectFactory) requesterFactory;
 880  
         }
 881  
         else
 882  
         {
 883  
             // need to adapt the factory for use by commons-pool
 884  0
             poolFactory = new KeyedPoolMessageRequesterFactoryAdapter(requesterFactory);
 885  
         }
 886  
 
 887  0
         requesters.setFactory(poolFactory);
 888  
 
 889  
         // we keep a reference to the unadapted factory, otherwise people might end
 890  
         // up with ClassCastExceptions on downcast to their implementation (sigh)
 891  0
         this.requesterFactory = requesterFactory;
 892  0
     }
 893  
 
 894  
     /**
 895  
      * <p>The connector creates a {@link MuleMessageFactory} lazily and holds a reference to it for
 896  
      * others to use.</p>
 897  
      * <p>The typical use case is to share a single {@link MuleMessageFactory} between all
 898  
      * {@link MessageDispatcher}, {@link MessageReceiver} and {@link MessageRequester} instances
 899  
      * belonging to this connector.</p>
 900  
      */
 901  
     public MuleMessageFactory getMuleMessageFactory() throws CreateException
 902  
     {
 903  0
         if (muleMessageFactory == null)
 904  
         {
 905  0
             muleMessageFactory = createMuleMessageFactory();
 906  
         }
 907  0
         return muleMessageFactory;
 908  
     }
 909  
 
 910  
     /**
 911  
      * The will cause the connector not to start when {@link #start()} is called. The
 912  
      * only way to start the connector is to call
 913  
      * {@link #setInitialStateStopped(boolean)} with 'false' and then calling
 914  
      * {@link #start()}. This flag is used internally since some connectors that rely
 915  
      * on external servers may need to wait for that server to become available
 916  
      * before starting.
 917  
      *
 918  
      * @return true if the connector is not to be started with normal lifecycle,
 919  
      *         flase otherwise
 920  
      * @since 3.0.0
 921  
      */
 922  
     public boolean isInitialStateStopped()
 923  
     {
 924  0
         return initialStateStopped;
 925  
     }
 926  
 
 927  
     /**
 928  
      * The will cause the connector not to start when {@link #start()} is called. The
 929  
      * only way to start the connector is to call
 930  
      * {@link #setInitialStateStopped(boolean)} with 'false' and then calling
 931  
      * {@link #start()}. This flag is used internally since some connectors that rely
 932  
      * on external servers may need to wait for that server to become available
 933  
      * before starting. The only time this method should be used is when a
 934  
      * subclassing connector needs to delay the start lifecycle due to a dependence
 935  
      * on an external system. Most users can ignore this.
 936  
      *
 937  
      * @param initialStateStopped true to stop the connector starting through normal lifecycle. It will
 938  
      *             be the responsibility of the code that sets this property to start the
 939  
      *             connector
 940  
      * @since 3.0.0
 941  
      */
 942  
     public void setInitialStateStopped(boolean initialStateStopped)
 943  
     {
 944  0
         this.initialStateStopped = initialStateStopped;
 945  0
     }
 946  
 
 947  
     /**
 948  
      * Returns the maximum number of dispatchers that can be concurrently active per
 949  
      * endpoint.
 950  
      *
 951  
      * @return max. number of active dispatchers
 952  
      */
 953  
     public int getMaxDispatchersActive()
 954  
     {
 955  0
         checkDispatchersInitialised();
 956  0
         return this.dispatchers.getMaxActive();
 957  
     }
 958  
 
 959  
     /**
 960  
      * Checks if the connector was initialised or not. Some connectors fields are created
 961  
      * during connector's initialization so this check should be used before accessing them.
 962  
      */
 963  
     private void checkDispatchersInitialised()
 964  
     {
 965  0
         if (dispatchers == null)
 966  
         {
 967  0
             throw new IllegalStateException("Dispatchers pool was not initialised");
 968  
         }
 969  0
     }
 970  
 
 971  
     /**
 972  
      * Returns the maximum number of dispatchers that can be concurrently active for
 973  
      * all endpoints.
 974  
      *
 975  
      * @return max. total number of active dispatchers
 976  
      */
 977  
     public int getMaxTotalDispatchers()
 978  
     {
 979  0
         checkDispatchersInitialised();
 980  0
         return this.dispatchers.getMaxTotal();
 981  
     }
 982  
 
 983  
     /**
 984  
      * Configures the maximum number of dispatchers that can be concurrently active
 985  
      * per endpoint
 986  
      *
 987  
      * @param maxActive max. number of active dispatchers
 988  
      */
 989  
     public void setMaxDispatchersActive(int maxActive)
 990  
     {
 991  0
         checkDispatchersInitialised();
 992  0
         this.dispatchers.setMaxActive(maxActive);
 993  
         // adjust maxIdle in tandem to avoid thrashing
 994  0
         this.dispatchers.setMaxIdle(maxActive);
 995  
         // this tells the pool to expire some objects eventually if we start
 996  
         // running out. This happens if one is using a lot of dynamic endpoints.
 997  0
         this.dispatchers.setMaxTotal(20 * maxActive);
 998  0
     }
 999  
 
 1000  
     private MessageDispatcher getDispatcher(OutboundEndpoint endpoint) throws MuleException
 1001  
     {
 1002  0
         if (!isStarted())
 1003  
         {
 1004  0
             throw new LifecycleException(CoreMessages.lifecycleErrorCannotUseConnector(getName(),
 1005  
                     lifecycleManager.getCurrentPhase()), this);
 1006  
         }
 1007  
 
 1008  0
         if (endpoint == null)
 1009  
         {
 1010  0
             throw new IllegalArgumentException("Endpoint must not be null");
 1011  
         }
 1012  
 
 1013  0
         if (!supportsProtocol(endpoint.getConnector().getProtocol()))
 1014  
         {
 1015  0
             throw new IllegalArgumentException(CoreMessages.connectorSchemeIncompatibleWithEndpointScheme(
 1016  
                     this.getProtocol(), endpoint.getEndpointURI().toString()).getMessage());
 1017  
         }
 1018  
 
 1019  0
         MessageDispatcher dispatcher = null;
 1020  
         try
 1021  
         {
 1022  0
             if (logger.isDebugEnabled())
 1023  
             {
 1024  0
                 logger.debug("Borrowing a dispatcher for endpoint: " + endpoint.getEndpointURI());
 1025  
             }
 1026  
 
 1027  0
             dispatcher = (MessageDispatcher) dispatchers.borrowObject(endpoint);
 1028  
 
 1029  0
             if (logger.isDebugEnabled())
 1030  
             {
 1031  0
                 logger.debug("Borrowed a dispatcher for endpoint: " + endpoint.getEndpointURI() + " = "
 1032  
                         + dispatcher.toString());
 1033  
             }
 1034  
 
 1035  0
             return dispatcher;
 1036  
         }
 1037  0
         catch (Exception ex)
 1038  
         {
 1039  0
             throw new ConnectorException(CoreMessages.connectorCausedError(), this, ex);
 1040  
         }
 1041  
         finally
 1042  
         {
 1043  0
             try
 1044  
             {
 1045  0
                 if (logger.isDebugEnabled())
 1046  
                 {
 1047  0
                     logger.debug("Borrowed dispatcher: " + ObjectUtils.toString(dispatcher, "null"));
 1048  
                 }
 1049  
             }
 1050  0
             catch (Exception ex)
 1051  
             {
 1052  0
                 throw new ConnectorException(CoreMessages.connectorCausedError(), this, ex);
 1053  0
             }
 1054  
         }
 1055  
     }
 1056  
 
 1057  
     private void returnDispatcher(OutboundEndpoint endpoint, MessageDispatcher dispatcher)
 1058  
     {
 1059  0
         if (endpoint != null && dispatcher != null)
 1060  
         {
 1061  0
             if (logger.isDebugEnabled())
 1062  
             {
 1063  0
                 logger.debug("Returning dispatcher for endpoint: " + endpoint.getEndpointURI() + " = "
 1064  
                         + dispatcher.toString());
 1065  
             }
 1066  
 
 1067  
             try
 1068  
             {
 1069  0
                 dispatchers.returnObject(endpoint, dispatcher);
 1070  
             }
 1071  0
             catch (Exception e)
 1072  
             {
 1073  
                 // ignore - if the dispatcher is broken, it will likely get cleaned
 1074  
                 // up by the factory
 1075  0
                 logger.error("Failed to dispose dispatcher for endpoint: " + endpoint
 1076  
                         + ". This will cause a memory leak. Please report to", e);
 1077  0
             }
 1078  
 
 1079  
         }
 1080  0
     }
 1081  
 
 1082  
     /**
 1083  
      * Returns the maximum number of requesters that can be concurrently active per
 1084  
      * endpoint.
 1085  
      *
 1086  
      * @return max. number of active requesters
 1087  
      */
 1088  
     public int getMaxRequestersActive()
 1089  
     {
 1090  0
         return this.requesters.getMaxActive();
 1091  
     }
 1092  
 
 1093  
     /**
 1094  
      * Configures the maximum number of requesters that can be concurrently active
 1095  
      * per endpoint
 1096  
      *
 1097  
      * @param maxActive max. number of active requesters
 1098  
      */
 1099  
     public void setMaxRequestersActive(int maxActive)
 1100  
     {
 1101  0
         this.requesters.setMaxActive(maxActive);
 1102  
         // adjust maxIdle in tandem to avoid thrashing
 1103  0
         this.requesters.setMaxIdle(maxActive);
 1104  
         // this tells the pool to expire some objects eventually if we start
 1105  
         // running out. This happens if one is using a lot of dynamic endpoints.
 1106  0
         this.requesters.setMaxTotal(20 * maxActive);
 1107  0
     }
 1108  
 
 1109  
     private MessageRequester getRequester(InboundEndpoint endpoint) throws MuleException
 1110  
     {
 1111  0
         if (!isStarted())
 1112  
         {
 1113  0
             throw new LifecycleException(CoreMessages.lifecycleErrorCannotUseConnector(getName(),
 1114  
                     lifecycleManager.getCurrentPhase()), this);
 1115  
         }
 1116  
 
 1117  0
         if (endpoint == null)
 1118  
         {
 1119  0
             throw new IllegalArgumentException("Endpoint must not be null");
 1120  
         }
 1121  
 
 1122  0
         if (!supportsProtocol(endpoint.getConnector().getProtocol()))
 1123  
         {
 1124  0
             throw new IllegalArgumentException(CoreMessages.connectorSchemeIncompatibleWithEndpointScheme(
 1125  
                     this.getProtocol(), endpoint.getEndpointURI().toString()).getMessage());
 1126  
         }
 1127  
 
 1128  0
         MessageRequester requester = null;
 1129  
         try
 1130  
         {
 1131  0
             if (logger.isDebugEnabled())
 1132  
             {
 1133  0
                 logger.debug("Borrowing a requester for endpoint: " + endpoint.getEndpointURI());
 1134  
             }
 1135  
 
 1136  0
             requester = (MessageRequester) requesters.borrowObject(endpoint);
 1137  
 
 1138  0
             if (logger.isDebugEnabled())
 1139  
             {
 1140  0
                 logger.debug("Borrowed a requester for endpoint: " + endpoint.getEndpointURI() + " = "
 1141  
                         + requester.toString());
 1142  
             }
 1143  
 
 1144  0
             return requester;
 1145  
         }
 1146  0
         catch (Exception ex)
 1147  
         {
 1148  0
             throw new ConnectorException(CoreMessages.connectorCausedError(), this, ex);
 1149  
         }
 1150  
         finally
 1151  
         {
 1152  0
             try
 1153  
             {
 1154  0
                 if (logger.isDebugEnabled())
 1155  
                 {
 1156  0
                     logger.debug("Borrowed requester: " + ObjectUtils.toString(requester, "null"));
 1157  
                 }
 1158  
             }
 1159  0
             catch (Exception ex)
 1160  
             {
 1161  0
                 throw new ConnectorException(CoreMessages.connectorCausedError(), this, ex);
 1162  0
             }
 1163  
         }
 1164  
     }
 1165  
 
 1166  
     private void returnRequester(InboundEndpoint endpoint, MessageRequester requester)
 1167  
     {
 1168  0
         if (endpoint != null && requester != null)
 1169  
         {
 1170  0
             if (logger.isDebugEnabled())
 1171  
             {
 1172  0
                 logger.debug("Returning requester for endpoint: " + endpoint.getEndpointURI() + " = "
 1173  
                         + requester.toString());
 1174  
             }
 1175  
 
 1176  
             try
 1177  
             {
 1178  0
                 requesters.returnObject(endpoint, requester);
 1179  
             }
 1180  0
             catch (Exception e)
 1181  
             {
 1182  
                 // ignore - if the requester is broken, it will likely get cleaned
 1183  
                 // up by the factory
 1184  0
                 logger.error("Failed to dispose requester for endpoint: " + endpoint
 1185  
                         + ". This will cause a memory leak. Please report to", e);
 1186  0
             }
 1187  
         }
 1188  
 
 1189  0
     }
 1190  
 
 1191  
     public void registerListener(InboundEndpoint endpoint,
 1192  
                                  MessageProcessor messageProcessorChain,
 1193  
                                  FlowConstruct flowConstruct) throws Exception
 1194  
     {
 1195  0
         if (endpoint == null)
 1196  
         {
 1197  0
             throw new IllegalArgumentException("The endpoint cannot be null when registering a listener");
 1198  
         }
 1199  
 
 1200  0
         if (messageProcessorChain == null)
 1201  
         {
 1202  0
             throw new IllegalArgumentException("The messageProcessorChain cannot be null when registering a listener");
 1203  
         }
 1204  
 
 1205  0
         EndpointURI endpointUri = endpoint.getEndpointURI();
 1206  0
         if (endpointUri == null)
 1207  
         {
 1208  0
             throw new ConnectorException(CoreMessages.endpointIsNullForListener(), this);
 1209  
         }
 1210  
 
 1211  0
         logger.info("Registering listener: " + flowConstruct.getName() + " on endpointUri: "
 1212  
                 + endpointUri.toString());
 1213  
 
 1214  0
         if (getReceiver(flowConstruct, endpoint) != null)
 1215  
         {
 1216  0
             throw new ConnectorException(CoreMessages.listenerAlreadyRegistered(endpointUri), this);
 1217  
         }
 1218  
 
 1219  0
         MessageReceiver receiver = createReceiver(flowConstruct, endpoint);
 1220  0
         receiver.setListener(messageProcessorChain);
 1221  
 
 1222  0
         Object receiverKey = getReceiverKey(flowConstruct, endpoint);
 1223  0
         receiver.setReceiverKey(receiverKey.toString());
 1224  
         // Since we're managing the creation we also need to initialise
 1225  0
         receiver.initialise();
 1226  0
         receivers.put(receiverKey, receiver);
 1227  
 
 1228  0
         if (isConnected())
 1229  
         {
 1230  0
             receiver.connect();
 1231  
         }
 1232  
 
 1233  0
         if (isStarted())
 1234  
         {
 1235  0
             receiver.start();
 1236  
         }
 1237  0
     }
 1238  
 
 1239  
     /**
 1240  
      * The method determines the key used to store the receiver against.
 1241  
      *
 1242  
      * @param flowConstruct the service for which the endpoint is being registered
 1243  
      * @param endpoint      the endpoint being registered for the service
 1244  
      * @return the key to store the newly created receiver against
 1245  
      */
 1246  
     protected Object getReceiverKey(FlowConstruct flowConstruct, InboundEndpoint endpoint)
 1247  
     {
 1248  0
         return StringUtils.defaultIfEmpty(endpoint.getEndpointURI().getFilterAddress(),
 1249  
                 endpoint.getEndpointURI().getAddress());
 1250  
     }
 1251  
 
 1252  
     public final void unregisterListener(InboundEndpoint endpoint, FlowConstruct flowConstruct) throws Exception
 1253  
     {
 1254  0
         if (endpoint == null)
 1255  
         {
 1256  0
             throw new IllegalArgumentException("The endpoint must not be null when you unregister a listener");
 1257  
         }
 1258  
 
 1259  0
         EndpointURI endpointUri = endpoint.getEndpointURI();
 1260  0
         if (endpointUri == null)
 1261  
         {
 1262  0
             throw new IllegalArgumentException(
 1263  
                     "The endpointUri must not be null when you unregister a listener");
 1264  
         }
 1265  
 
 1266  0
         if (logger.isInfoEnabled())
 1267  
         {
 1268  0
             logger.info("Removing listener on endpointUri: " + endpointUri);
 1269  
         }
 1270  
 
 1271  0
         if (receivers != null && !receivers.isEmpty())
 1272  
         {
 1273  0
             MessageReceiver receiver = receivers.remove(getReceiverKey(flowConstruct, endpoint));
 1274  0
             if (receiver != null)
 1275  
             {
 1276  0
                 if (isConnected())
 1277  
                 {
 1278  0
                     receiver.disconnect();
 1279  
                 }
 1280  
 
 1281  0
                 if (isStarted())
 1282  
                 {
 1283  0
                     receiver.stop();
 1284  
                 }
 1285  0
                 destroyReceiver(receiver, endpoint);
 1286  0
                 doUnregisterListener(flowConstruct, endpoint, receiver);
 1287  
             }
 1288  
         }
 1289  0
     }
 1290  
 
 1291  
     protected void doUnregisterListener(FlowConstruct flowConstruct, InboundEndpoint endpoint, MessageReceiver receiver)
 1292  
     {
 1293  
         // Template method
 1294  0
     }
 1295  
 
 1296  
     /**
 1297  
      * Getter for property 'dispatcherThreadingProfile'.
 1298  
      *
 1299  
      * @return Value for property 'dispatcherThreadingProfile'.
 1300  
      */
 1301  
     public ThreadingProfile getDispatcherThreadingProfile()
 1302  
     {
 1303  0
         if (dispatcherThreadingProfile == null && muleContext != null)
 1304  
         {
 1305  0
             dispatcherThreadingProfile = muleContext.getDefaultMessageDispatcherThreadingProfile();
 1306  
         }
 1307  0
         return dispatcherThreadingProfile;
 1308  
     }
 1309  
 
 1310  
     /**
 1311  
      * Setter for property 'dispatcherThreadingProfile'.
 1312  
      *
 1313  
      * @param dispatcherThreadingProfile Value to set for property
 1314  
      *                                   'dispatcherThreadingProfile'.
 1315  
      */
 1316  
     public void setDispatcherThreadingProfile(ThreadingProfile dispatcherThreadingProfile)
 1317  
     {
 1318  0
         this.dispatcherThreadingProfile = dispatcherThreadingProfile;
 1319  0
     }
 1320  
 
 1321  
     /**
 1322  
      * Getter for property 'requesterThreadingProfile'.
 1323  
      *
 1324  
      * @return Value for property 'requesterThreadingProfile'.
 1325  
      */
 1326  
     public ThreadingProfile getRequesterThreadingProfile()
 1327  
     {
 1328  0
         if (requesterThreadingProfile == null && muleContext != null)
 1329  
         {
 1330  0
             requesterThreadingProfile = muleContext.getDefaultMessageRequesterThreadingProfile();
 1331  
         }
 1332  0
         return requesterThreadingProfile;
 1333  
     }
 1334  
 
 1335  
     /**
 1336  
      * Setter for property 'requesterThreadingProfile'.
 1337  
      *
 1338  
      * @param requesterThreadingProfile Value to set for property
 1339  
      *                                  'requesterThreadingProfile'.
 1340  
      */
 1341  
     public void setRequesterThreadingProfile(ThreadingProfile requesterThreadingProfile)
 1342  
     {
 1343  0
         this.requesterThreadingProfile = requesterThreadingProfile;
 1344  0
     }
 1345  
 
 1346  
     /**
 1347  
      * Getter for property 'receiverThreadingProfile'.
 1348  
      *
 1349  
      * @return Value for property 'receiverThreadingProfile'.
 1350  
      */
 1351  
     public ThreadingProfile getReceiverThreadingProfile()
 1352  
     {
 1353  0
         if (receiverThreadingProfile == null && muleContext != null)
 1354  
         {
 1355  0
             receiverThreadingProfile = muleContext.getDefaultMessageReceiverThreadingProfile();
 1356  
         }
 1357  0
         return receiverThreadingProfile;
 1358  
     }
 1359  
 
 1360  
     /**
 1361  
      * Setter for property 'receiverThreadingProfile'.
 1362  
      *
 1363  
      * @param receiverThreadingProfile Value to set for property
 1364  
      *                                 'receiverThreadingProfile'.
 1365  
      */
 1366  
     public void setReceiverThreadingProfile(ThreadingProfile receiverThreadingProfile)
 1367  
     {
 1368  0
         this.receiverThreadingProfile = receiverThreadingProfile;
 1369  0
     }
 1370  
 
 1371  
     public void destroyReceiver(MessageReceiver receiver, ImmutableEndpoint endpoint) throws Exception
 1372  
     {
 1373  0
         receiver.dispose();
 1374  0
     }
 1375  
 
 1376  
     protected abstract void doInitialise() throws InitialisationException;
 1377  
 
 1378  
     /**
 1379  
      * Template method to perform any work when destroying the connectoe
 1380  
      */
 1381  
     protected abstract void doDispose();
 1382  
 
 1383  
     /**
 1384  
      * Template method to perform any work when starting the connectoe
 1385  
      *
 1386  
      * @throws MuleException if the method fails
 1387  
      */
 1388  
     protected abstract void doStart() throws MuleException;
 1389  
 
 1390  
     /**
 1391  
      * Template method to perform any work when stopping the connectoe
 1392  
      *
 1393  
      * @throws MuleException if the method fails
 1394  
      */
 1395  
     protected abstract void doStop() throws MuleException;
 1396  
 
 1397  
     public List<Transformer> getDefaultInboundTransformers(ImmutableEndpoint endpoint)
 1398  
     {
 1399  0
         if (serviceDescriptor == null)
 1400  
         {
 1401  0
             throw new RuntimeException("serviceDescriptor not initialized");
 1402  
         }
 1403  0
         return TransformerUtils.getDefaultInboundTransformers(serviceDescriptor, endpoint);
 1404  
     }
 1405  
 
 1406  
     public List<Transformer> getDefaultResponseTransformers(ImmutableEndpoint endpoint)
 1407  
     {
 1408  0
         if (serviceDescriptor == null)
 1409  
         {
 1410  0
             throw new RuntimeException("serviceDescriptor not initialized");
 1411  
         }
 1412  0
         return TransformerUtils.getDefaultResponseTransformers(serviceDescriptor, endpoint);
 1413  
     }
 1414  
 
 1415  
     public List<Transformer> getDefaultOutboundTransformers(ImmutableEndpoint endpoint)
 1416  
     {
 1417  0
         if (serviceDescriptor == null)
 1418  
         {
 1419  0
             throw new RuntimeException("serviceDescriptor not initialized");
 1420  
         }
 1421  0
         return TransformerUtils.getDefaultOutboundTransformers(serviceDescriptor, endpoint);
 1422  
     }
 1423  
 
 1424  
     /**
 1425  
      * Getter for property 'replyToHandler'.
 1426  
      *
 1427  
      * @return Value for property 'replyToHandler'.
 1428  
      */
 1429  
     public ReplyToHandler getReplyToHandler(ImmutableEndpoint endpoint)
 1430  
     {
 1431  0
         return new DefaultReplyToHandler(getDefaultResponseTransformers(endpoint), muleContext);
 1432  
     }
 1433  
 
 1434  
     /**
 1435  
      * Fires a server notification to all registered listeners
 1436  
      *
 1437  
      * @param notification the notification to fire.
 1438  
      */
 1439  
     public void fireNotification(ServerNotification notification)
 1440  
     {
 1441  0
         cachedNotificationHandler.fireNotification(notification);
 1442  0
     }
 1443  
 
 1444  
     public boolean isResponseEnabled()
 1445  
     {
 1446  0
         return false;
 1447  
     }
 1448  
 
 1449  
     public MessageReceiver getReceiver(FlowConstruct flowConstruct, InboundEndpoint endpoint)
 1450  
     {
 1451  0
         if (receivers != null)
 1452  
         {
 1453  0
             Object key = getReceiverKey(flowConstruct, endpoint);
 1454  0
             if (key != null)
 1455  
             {
 1456  0
                 return receivers.get(key);
 1457  
             }
 1458  
             else
 1459  
             {
 1460  0
                 throw new RuntimeException("getReceiverKey() returned a null key");
 1461  
             }
 1462  
         }
 1463  
         else
 1464  
         {
 1465  0
             throw new RuntimeException("Connector has not been initialized.");
 1466  
         }
 1467  
     }
 1468  
 
 1469  
     /**
 1470  
      * Getter for property 'receivers'.
 1471  
      *
 1472  
      * @return Value for property 'receivers'.
 1473  
      */
 1474  
     public Map<Object, MessageReceiver> getReceivers()
 1475  
     {
 1476  0
         return Collections.unmodifiableMap(receivers);
 1477  
     }
 1478  
 
 1479  
     public MessageReceiver lookupReceiver(String key)
 1480  
     {
 1481  0
         if (key != null)
 1482  
         {
 1483  0
             return receivers.get(key);
 1484  
         }
 1485  
         else
 1486  
         {
 1487  0
             throw new IllegalArgumentException("Receiver key must not be null");
 1488  
         }
 1489  
     }
 1490  
 
 1491  
     public MessageReceiver[] getReceivers(String wildcardExpression)
 1492  
     {
 1493  0
         WildcardFilter filter = new WildcardFilter(wildcardExpression);
 1494  0
         filter.setCaseSensitive(false);
 1495  
 
 1496  0
         List<MessageReceiver> found = new ArrayList<MessageReceiver>();
 1497  
 
 1498  0
         for (Map.Entry<Object, MessageReceiver> e : receivers.entrySet())
 1499  
         {
 1500  0
             if (filter.accept(e.getKey()))
 1501  
             {
 1502  0
                 found.add(e.getValue());
 1503  
             }
 1504  
         }
 1505  
 
 1506  0
         return CollectionUtils.toArrayOfComponentType(found, MessageReceiver.class);
 1507  
     }
 1508  
 
 1509  
     public void connect() throws Exception
 1510  
     {
 1511  0
         if (lifecycleManager.getState().isDisposed())
 1512  
         {
 1513  0
             throw new LifecycleException(CoreMessages.lifecycleErrorCannotUseConnector(getName(),
 1514  
                     lifecycleManager.getCurrentPhase()), this);
 1515  
         }
 1516  
 
 1517  0
         if (isConnected())
 1518  
         {
 1519  0
             return;
 1520  
         }
 1521  
 
 1522  0
         if (logger.isDebugEnabled())
 1523  
         {
 1524  0
             logger.debug("Connecting: " + this);
 1525  
         }
 1526  
 
 1527  0
         RetryCallback callback = new RetryCallback()
 1528  0
         {
 1529  
             public void doWork(RetryContext context) throws Exception
 1530  
             {
 1531  
                 // Try validateConnection() rather than connect() which may be a less expensive operation while we're retrying.
 1532  0
                 if (validateConnections && context.getLastFailure() instanceof ConnectException)
 1533  
                 {
 1534  0
                     Connectable failed = ((ConnectException) context.getLastFailure()).getFailed();                    
 1535  0
                     if (!failed.validateConnection(context).isOk())
 1536  
                     {
 1537  0
                         throw new ConnectException(
 1538  
                                 MessageFactory.createStaticMessage("Still unable to connect to resource " + failed.getClass().getName()),
 1539  
                                 context.getLastFailure(), failed);
 1540  
                     }
 1541  
                 }
 1542  0
                 doConnect();
 1543  0
                 setConnected(true);
 1544  
 
 1545  0
                 logger.info("Connected: " + getWorkDescription());
 1546  
 
 1547  0
                 if (startOnConnect)
 1548  
                 {
 1549  0
                     startAfterConnect();
 1550  
                 }
 1551  0
             }
 1552  
 
 1553  
             public String getWorkDescription()
 1554  
             {
 1555  0
                 return getConnectionDescription();
 1556  
             }
 1557  
         };
 1558  
 
 1559  0
         retryPolicyTemplate.execute(callback, muleContext.getWorkManager());
 1560  0
     }
 1561  
 
 1562  
     /**
 1563  
      * Override this method to test whether the connector is able to connect to its
 1564  
      * resource(s). This will allow a retry policy to go into effect in the case of
 1565  
      * failure.
 1566  
      *
 1567  
      * @return retry context with a success flag or failure details
 1568  
      * @see RetryContext#isOk()
 1569  
      * @see RetryContext#getLastFailure()
 1570  
      */
 1571  
     public RetryContext validateConnection(RetryContext retryContext)
 1572  
     {
 1573  0
         retryContext.setOk();
 1574  0
         return retryContext;
 1575  
     }
 1576  
 
 1577  
     public void disconnect() throws Exception
 1578  
     {
 1579  0
         startOnConnect = isStarted();
 1580  
 
 1581  
         try
 1582  
         {
 1583  0
             if (receivers != null)
 1584  
             {
 1585  0
                 for (MessageReceiver receiver : receivers.values())
 1586  
                 {
 1587  0
                     if (logger.isDebugEnabled())
 1588  
                     {
 1589  0
                         logger.debug("Disconnecting receiver on endpoint: "
 1590  
                                 + receiver.getEndpoint().getEndpointURI());
 1591  
                     }
 1592  0
                     receiver.disconnect();
 1593  
                 }
 1594  
             }
 1595  0
             this.doDisconnect();
 1596  
         }
 1597  
         finally
 1598  
         {
 1599  0
             if (receivers != null)
 1600  
             {
 1601  0
                 for (MessageReceiver receiver : receivers.values())
 1602  
                 {
 1603  
                     // TODO MULE-3969
 1604  0
                     if (receiver instanceof AbstractMessageReceiver
 1605  
                             && ((AbstractMessageReceiver) receiver).isStarted())
 1606  
                     {
 1607  0
                         if (logger.isDebugEnabled())
 1608  
                         {
 1609  0
                             logger.debug("Stopping receiver on endpoint: "
 1610  
                                     + receiver.getEndpoint().getEndpointURI());
 1611  
                         }
 1612  0
                         receiver.stop();
 1613  
                     }
 1614  
                 }
 1615  
             }
 1616  
         }
 1617  
 
 1618  0
         connected.set(false);
 1619  0
         if (logger.isInfoEnabled())
 1620  
         {
 1621  0
             logger.info("Disconnected: " + this.getConnectionDescription());
 1622  
         }
 1623  0
         this.fireNotification(new ConnectionNotification(this, getConnectEventId(),
 1624  
                 ConnectionNotification.CONNECTION_DISCONNECTED));
 1625  0
     }
 1626  
 
 1627  
     public String getConnectionDescription()
 1628  
     {
 1629  0
         return this.toString();
 1630  
     }
 1631  
 
 1632  
     public final boolean isConnected()
 1633  
     {
 1634  0
         return connected.get();
 1635  
     }
 1636  
 
 1637  
     public final void setConnected(boolean flag)
 1638  
     {
 1639  0
         connected.set(flag);
 1640  0
     }
 1641  
 
 1642  
     /**
 1643  
      * Template method where any connections should be made for the connector
 1644  
      *
 1645  
      * @throws Exception
 1646  
      */
 1647  
     protected abstract void doConnect() throws Exception;
 1648  
 
 1649  
     /**
 1650  
      * Template method where any connected resources used by the connector should be
 1651  
      * disconnected
 1652  
      *
 1653  
      * @throws Exception
 1654  
      */
 1655  
     protected abstract void doDisconnect() throws Exception;
 1656  
 
 1657  
     /**
 1658  
      * The resource id used when firing ConnectEvents from this connector
 1659  
      *
 1660  
      * @return the resource id used when firing ConnectEvents from this connector
 1661  
      */
 1662  
     protected String getConnectEventId()
 1663  
     {
 1664  0
         return getName();
 1665  
     }
 1666  
 
 1667  
     /**
 1668  
      * For better throughput when using TransactedMessageReceivers this will enable a
 1669  
      * number of concurrent receivers, based on the value returned by
 1670  
      * {@link #getNumberOfConcurrentTransactedReceivers()}. This property is used by
 1671  
      * transports that support transactions, specifically receivers that extend the
 1672  
      * TransactedPollingMessageReceiver.
 1673  
      *
 1674  
      * @return true if multiple receivers will be enabled for this connection
 1675  
      */
 1676  
     public boolean isCreateMultipleTransactedReceivers()
 1677  
     {
 1678  0
         return createMultipleTransactedReceivers;
 1679  
     }
 1680  
 
 1681  
     /**
 1682  
      * @param createMultipleTransactedReceivers
 1683  
      *         if true, multiple receivers will be
 1684  
      *         created for this connection
 1685  
      * @see #isCreateMultipleTransactedReceivers()
 1686  
      */
 1687  
     public void setCreateMultipleTransactedReceivers(boolean createMultipleTransactedReceivers)
 1688  
     {
 1689  0
         this.createMultipleTransactedReceivers = createMultipleTransactedReceivers;
 1690  0
     }
 1691  
 
 1692  
     /**
 1693  
      * Returns the number of concurrent receivers that will be launched when
 1694  
      * {@link #isCreateMultipleTransactedReceivers()} returns <code>true</code>.
 1695  
      *
 1696  
      * @see #DEFAULT_NUM_CONCURRENT_TX_RECEIVERS
 1697  
      */
 1698  
     public int getNumberOfConcurrentTransactedReceivers()
 1699  
     {
 1700  0
         return this.numberOfConcurrentTransactedReceivers;
 1701  
     }
 1702  
 
 1703  
     /**
 1704  
      * @param count the number of concurrent transacted receivers to start
 1705  
      * @see #getNumberOfConcurrentTransactedReceivers()
 1706  
      */
 1707  
     public void setNumberOfConcurrentTransactedReceivers(int count)
 1708  
     {
 1709  0
         this.numberOfConcurrentTransactedReceivers = count;
 1710  0
     }
 1711  
 
 1712  
     public void setDynamicNotification(boolean dynamic)
 1713  
     {
 1714  0
         dynamicNotification = dynamic;
 1715  0
     }
 1716  
 
 1717  
     protected void updateCachedNotificationHandler()
 1718  
     {
 1719  0
         if (null != muleContext)
 1720  
         {
 1721  0
             if (dynamicNotification)
 1722  
             {
 1723  0
                 cachedNotificationHandler = muleContext.getNotificationManager();
 1724  
             }
 1725  
             else
 1726  
             {
 1727  0
                 cachedNotificationHandler = new OptimisedNotificationHandler(
 1728  
                         muleContext.getNotificationManager(), EndpointMessageNotification.class);
 1729  
             }
 1730  
         }
 1731  0
     }
 1732  
 
 1733  
     public boolean isEnableMessageEvents()
 1734  
     {
 1735  0
         return cachedNotificationHandler.isNotificationEnabled(EndpointMessageNotification.class);
 1736  
     }
 1737  
 
 1738  
     /**
 1739  
      * Registers other protocols 'understood' by this connector. These must contain
 1740  
      * scheme meta info. Any protocol registered must begin with the protocol of this
 1741  
      * connector, i.e. If the connector is axis the protocol for jms over axis will
 1742  
      * be axis:jms. Here, 'axis' is the scheme meta info and 'jms' is the protocol.
 1743  
      * If the protocol argument does not start with the connector's protocol, it will
 1744  
      * be appended.
 1745  
      *
 1746  
      * @param protocol the supported protocol to register
 1747  
      */
 1748  
     public void registerSupportedProtocol(String protocol)
 1749  
     {
 1750  0
         protocol = protocol.toLowerCase();
 1751  0
         if (protocol.startsWith(getProtocol().toLowerCase()))
 1752  
         {
 1753  0
             registerSupportedProtocolWithoutPrefix(protocol);
 1754  
         }
 1755  
         else
 1756  
         {
 1757  0
             supportedProtocols.add(getProtocol().toLowerCase() + ":" + protocol);
 1758  
         }
 1759  0
     }
 1760  
 
 1761  
     /**
 1762  
      * Used by Meta endpoint descriptors to register support for endpoint of the meta
 1763  
      * endpoint type. For example an RSS endpoint uses the Http connector. By
 1764  
      * registering 'rss' as a supported meta protocol, this connector can be used
 1765  
      * when creating RSS endpoints.
 1766  
      *
 1767  
      * @param protocol the meta protocol that can be used with this connector
 1768  
      * @since 3.0.0
 1769  
      */
 1770  
     public void registerSupportedMetaProtocol(String protocol)
 1771  
     {
 1772  0
         supportedProtocols.add(protocol.toLowerCase() + ":" + getProtocol().toLowerCase());
 1773  
 
 1774  0
     }
 1775  
 
 1776  
     /**
 1777  
      * Registers other protocols 'understood' by this connector. These must contain
 1778  
      * scheme meta info. Unlike the {@link #registerSupportedProtocol(String)}
 1779  
      * method, this allows you to register protocols that are not prefixed with the
 1780  
      * connector protocol. This is useful where you use a Service Finder to discover
 1781  
      * which Transport implementation to use. For example the 'wsdl' transport is a
 1782  
      * generic 'finder' transport that will use Axis or CXF to create the WSDL
 1783  
      * client. These transport protocols would be wsdl-axis and wsdl-cxf, but they
 1784  
      * can all support 'wsdl' protocol too.
 1785  
      *
 1786  
      * @param protocol the supported protocol to register
 1787  
      */
 1788  
     protected void registerSupportedProtocolWithoutPrefix(String protocol)
 1789  
     {
 1790  0
         supportedProtocols.add(protocol.toLowerCase());
 1791  0
     }
 1792  
 
 1793  
     public void unregisterSupportedProtocol(String protocol)
 1794  
     {
 1795  0
         protocol = protocol.toLowerCase();
 1796  0
         if (protocol.startsWith(getProtocol().toLowerCase()))
 1797  
         {
 1798  0
             supportedProtocols.remove(protocol);
 1799  
         }
 1800  
         else
 1801  
         {
 1802  0
             supportedProtocols.remove(getProtocol().toLowerCase() + ":" + protocol);
 1803  
         }
 1804  0
     }
 1805  
 
 1806  
     /**
 1807  
      * @return true if the protocol is supported by this connector.
 1808  
      */
 1809  
     public boolean supportsProtocol(String protocol)
 1810  
     {
 1811  0
         return supportedProtocols.contains(protocol.toLowerCase());
 1812  
     }
 1813  
 
 1814  
     /**
 1815  
      * Returns an unmodifiable list of the protocols supported by this connector
 1816  
      *
 1817  
      * @return an unmodifiable list of the protocols supported by this connector
 1818  
      */
 1819  
     public List getSupportedProtocols()
 1820  
     {
 1821  0
         return Collections.unmodifiableList(supportedProtocols);
 1822  
     }
 1823  
 
 1824  
     /**
 1825  
      * Sets A list of protocols that the connector can accept
 1826  
      *
 1827  
      * @param supportedProtocols
 1828  
      */
 1829  
     public void setSupportedProtocols(List supportedProtocols)
 1830  
     {
 1831  0
         for (Iterator iterator = supportedProtocols.iterator(); iterator.hasNext();)
 1832  
         {
 1833  0
             String s = (String) iterator.next();
 1834  0
             registerSupportedProtocol(s);
 1835  0
         }
 1836  0
     }
 1837  
 
 1838  
     /**
 1839  
      * Returns a work manager for message receivers.
 1840  
      */
 1841  
     protected WorkManager getReceiverWorkManager() throws MuleException
 1842  
     {
 1843  0
         return (WorkManager) receiverWorkManager.get();
 1844  
     }
 1845  
 
 1846  
     /**
 1847  
      * Returns a work manager for message dispatchers.
 1848  
      *
 1849  
      * @throws MuleException in case of error
 1850  
      */
 1851  
     protected WorkManager getDispatcherWorkManager() throws MuleException
 1852  
     {
 1853  0
         return (WorkManager) dispatcherWorkManager.get();
 1854  
     }
 1855  
 
 1856  
     /**
 1857  
      * Returns a work manager for message requesters.
 1858  
      *
 1859  
      * @throws MuleException in case of error
 1860  
      */
 1861  
     protected WorkManager getRequesterWorkManager() throws MuleException
 1862  
     {
 1863  0
         return (WorkManager) requesterWorkManager.get();
 1864  
     }
 1865  
 
 1866  
     /**
 1867  
      * Returns a Scheduler service for periodic tasks, currently limited to internal
 1868  
      * use. Note: getScheduler() currently conflicts with the same method in the
 1869  
      * Quartz transport
 1870  
      */
 1871  
     public ScheduledExecutorService getScheduler()
 1872  
     {
 1873  0
         return scheduler;
 1874  
     }
 1875  
 
 1876  
     protected ScheduledExecutorService createScheduler()
 1877  
     {
 1878  
         // Use connector's classloader so that other temporary classloaders
 1879  
         // aren't used when things are started lazily or from elsewhere.
 1880  0
         ThreadFactory threadFactory = new NamedThreadFactory(this.getName() + ".scheduler", this.getClass()
 1881  
                 .getClassLoader());
 1882  0
         ScheduledThreadPoolExecutor newExecutor = new ScheduledThreadPoolExecutor(4, threadFactory);
 1883  0
         newExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
 1884  0
         newExecutor.setKeepAliveTime(this.getReceiverThreadingProfile().getThreadTTL(), TimeUnit.MILLISECONDS);
 1885  0
         newExecutor.allowCoreThreadTimeOut(true);
 1886  0
         return newExecutor;
 1887  
     }
 1888  
 
 1889  
     /**
 1890  
      * Getter for property 'sessionHandler'.
 1891  
      *
 1892  
      * @return Value for property 'sessionHandler'.
 1893  
      */
 1894  
     public SessionHandler getSessionHandler()
 1895  
     {
 1896  0
         return sessionHandler;
 1897  
     }
 1898  
 
 1899  
     /**
 1900  
      * Setter for property 'sessionHandler'.
 1901  
      *
 1902  
      * @param sessionHandler Value to set for property 'sessionHandler'.
 1903  
      */
 1904  
     public void setSessionHandler(SessionHandler sessionHandler)
 1905  
     {
 1906  0
         this.sessionHandler = sessionHandler;
 1907  0
     }
 1908  
 
 1909  
     public void workAccepted(WorkEvent event)
 1910  
     {
 1911  0
         this.handleWorkException(event, "workAccepted");
 1912  0
     }
 1913  
 
 1914  
     public void workRejected(WorkEvent event)
 1915  
     {
 1916  0
         this.handleWorkException(event, "workRejected");
 1917  0
     }
 1918  
 
 1919  
     public void workStarted(WorkEvent event)
 1920  
     {
 1921  0
         this.handleWorkException(event, "workStarted");
 1922  0
     }
 1923  
 
 1924  
     public void workCompleted(WorkEvent event)
 1925  
     {
 1926  0
         this.handleWorkException(event, "workCompleted");
 1927  0
     }
 1928  
 
 1929  
     protected void handleWorkException(WorkEvent event, String type)
 1930  
     {
 1931  0
         if (event == null)
 1932  
         {
 1933  0
             return;
 1934  
         }
 1935  
 
 1936  0
         Throwable e = event.getException();
 1937  
 
 1938  0
         if (e == null)
 1939  
         {
 1940  0
             return;
 1941  
         }
 1942  
 
 1943  0
         if (e.getCause() != null)
 1944  
         {
 1945  0
             e = e.getCause();
 1946  
         }
 1947  
 
 1948  0
         logger.error("Work caused exception on '" + type + "'. Work being executed was: "
 1949  
                 + event.getWork().toString());
 1950  
 
 1951  0
         if (e instanceof Exception)
 1952  
         {
 1953  0
             this.handleException((Exception) e);
 1954  
         }
 1955  
         else
 1956  
         {
 1957  0
             throw new MuleRuntimeException(CoreMessages.connectorCausedError(this.getName()), e);
 1958  
         }
 1959  0
     }
 1960  
 
 1961  
     /**
 1962  
      * This method will return the dispatcher to the pool or, if the payload is an
 1963  
      * inputstream, replace the payload with a new DelegatingInputStream which
 1964  
      * returns the dispatcher to the pool when the stream is closed.
 1965  
      *
 1966  
      * @param endpoint
 1967  
      * @param dispatcher
 1968  
      * @param result
 1969  
      */
 1970  
     protected void setupDispatchReturn(final OutboundEndpoint endpoint,
 1971  
                                        final MessageDispatcher dispatcher,
 1972  
                                        MuleMessage result)
 1973  
     {
 1974  0
         if (result != null && result.getPayload() instanceof InputStream)
 1975  
         {
 1976  0
             DelegatingInputStream is = new DelegatingInputStream((InputStream) result.getPayload())
 1977  0
             {
 1978  
                 @Override
 1979  
                 public void close() throws IOException
 1980  
                 {
 1981  
                     try
 1982  
                     {
 1983  0
                         super.close();
 1984  
                     }
 1985  
                     finally
 1986  
                     {
 1987  0
                         returnDispatcher(endpoint, dispatcher);
 1988  0
                     }
 1989  0
                 }
 1990  
             };
 1991  0
             result.setPayload(is);
 1992  0
         }
 1993  
         else
 1994  
         {
 1995  
 
 1996  0
             this.returnDispatcher(endpoint, dispatcher);
 1997  
         }
 1998  0
     }
 1999  
 
 2000  
     public MuleMessage request(String uri, long timeout) throws Exception
 2001  
     {
 2002  0
         return request(getMuleContext().getEndpointFactory().getInboundEndpoint(uri),
 2003  
                 timeout);
 2004  
     }
 2005  
 
 2006  
     public MuleMessage request(InboundEndpoint endpoint, long timeout) throws Exception
 2007  
     {
 2008  0
         MessageRequester requester = null;
 2009  0
         MuleMessage result = null;
 2010  
 
 2011  
         try
 2012  
         {
 2013  0
             requester = this.getRequester(endpoint);
 2014  0
             result = requester.request(timeout);
 2015  0
             return result;
 2016  
         }
 2017  
         finally
 2018  
         {
 2019  0
             setupRequestReturn(endpoint, requester, result);
 2020  
         }
 2021  
     }
 2022  
 
 2023  
     /**
 2024  
      * This method will return the requester to the pool or, if the payload is an
 2025  
      * inputstream, replace the payload with a new DelegatingInputStream which
 2026  
      * returns the requester to the pool when the stream is closed.
 2027  
      *
 2028  
      * @param endpoint
 2029  
      * @param requester
 2030  
      * @param result
 2031  
      */
 2032  
     protected void setupRequestReturn(final InboundEndpoint endpoint,
 2033  
                                       final MessageRequester requester,
 2034  
                                       MuleMessage result)
 2035  
     {
 2036  0
         if (result != null && result.getPayload() instanceof InputStream)
 2037  
         {
 2038  0
             DelegatingInputStream is = new DelegatingInputStream((InputStream) result.getPayload())
 2039  0
             {
 2040  
                 @Override
 2041  
                 public void close() throws IOException
 2042  
                 {
 2043  
                     try
 2044  
                     {
 2045  0
                         super.close();
 2046  
                     }
 2047  
                     finally
 2048  
                     {
 2049  0
                         returnRequester(endpoint, requester);
 2050  0
                     }
 2051  0
                 }
 2052  
             };
 2053  0
             result.setPayload(is);
 2054  0
         }
 2055  
         else
 2056  
         {
 2057  
 
 2058  0
             this.returnRequester(endpoint, requester);
 2059  
         }
 2060  0
     }
 2061  
 
 2062  
     // -------- Methods from the removed AbstractServiceEnabled Connector
 2063  
 
 2064  
     /**
 2065  
      * When this connector is created via the
 2066  
      * {@link org.mule.transport.service.TransportFactory} the endpoint used to
 2067  
      * determine the connector type is passed to this method so that any properties
 2068  
      * set on the endpoint that can be used to initialise the connector are made
 2069  
      * available.
 2070  
      *
 2071  
      * @param endpointUri the {@link EndpointURI} use to create this connector
 2072  
      * @throws InitialisationException If there are any problems with the
 2073  
      *                                 configuration set on the Endpoint or if another exception is
 2074  
      *                                 thrown it is wrapped in an InitialisationException.
 2075  
      */
 2076  
     public void initialiseFromUrl(EndpointURI endpointUri) throws InitialisationException
 2077  
     {
 2078  0
         if (!supportsProtocol(endpointUri.getFullScheme()))
 2079  
         {
 2080  0
             throw new InitialisationException(CoreMessages.schemeNotCompatibleWithConnector(
 2081  
                     endpointUri.getFullScheme(), this.getClass()), this);
 2082  
         }
 2083  0
         Properties props = new Properties();
 2084  0
         props.putAll(endpointUri.getParams());
 2085  
         // auto set username and password
 2086  0
         if (endpointUri.getUserInfo() != null)
 2087  
         {
 2088  0
             props.setProperty("username", endpointUri.getUser());
 2089  0
             String passwd = endpointUri.getPassword();
 2090  0
             if (passwd != null)
 2091  
             {
 2092  0
                 props.setProperty("password", passwd);
 2093  
             }
 2094  
         }
 2095  0
         String host = endpointUri.getHost();
 2096  0
         if (host != null)
 2097  
         {
 2098  0
             props.setProperty("hostname", host);
 2099  0
             props.setProperty("host", host);
 2100  
         }
 2101  0
         if (endpointUri.getPort() > -1)
 2102  
         {
 2103  0
             props.setProperty("port", String.valueOf(endpointUri.getPort()));
 2104  
         }
 2105  
 
 2106  0
         org.mule.util.BeanUtils.populateWithoutFail(this, props, true);
 2107  
 
 2108  0
         setName(new ObjectNameHelper(muleContext).getConnectorName(this));
 2109  
         // initialise();
 2110  0
     }
 2111  
 
 2112  
     /**
 2113  
      * Initialises this connector from its {@link TransportServiceDescriptor} This
 2114  
      * will be called before the {@link #doInitialise()} method is called.
 2115  
      *
 2116  
      * @throws InitialisationException InitialisationException If there are any
 2117  
      *                                 problems with the configuration or if another exception is thrown
 2118  
      *                                 it is wrapped in an InitialisationException.
 2119  
      */
 2120  
     protected synchronized void initFromServiceDescriptor() throws InitialisationException
 2121  
     {
 2122  
         try
 2123  
         {
 2124  0
             serviceDescriptor = (TransportServiceDescriptor) muleContext.getRegistry()
 2125  
                     .lookupServiceDescriptor(ServiceType.TRANSPORT, getProtocol().toLowerCase(), serviceOverrides);
 2126  0
             if (serviceDescriptor == null)
 2127  
             {
 2128  0
                 throw new ServiceException(CoreMessages.noServiceTransportDescriptor(getProtocol()));
 2129  
             }
 2130  
 
 2131  0
             if (logger.isDebugEnabled())
 2132  
             {
 2133  0
                 logger.debug("Loading DispatcherFactory for connector: " + getName() + " ("
 2134  
                         + getClass().getName() + ")");
 2135  
             }
 2136  
 
 2137  0
             MessageDispatcherFactory df = serviceDescriptor.createDispatcherFactory();
 2138  0
             if (df != null)
 2139  
             {
 2140  0
                 this.setDispatcherFactory(df);
 2141  
             }
 2142  0
             else if (logger.isDebugEnabled())
 2143  
             {
 2144  0
                 logger.debug("Transport '" + getProtocol() + "' will not support outbound endpoints: ");
 2145  
             }
 2146  
 
 2147  0
             if (logger.isDebugEnabled())
 2148  
             {
 2149  0
                 logger.debug("Loading RequesterFactory for connector: " + getName() + " ("
 2150  
                         + getClass().getName() + ")");
 2151  
             }
 2152  
 
 2153  0
             MessageRequesterFactory rf = serviceDescriptor.createRequesterFactory();
 2154  0
             if (rf != null)
 2155  
             {
 2156  0
                 this.setRequesterFactory(rf);
 2157  
             }
 2158  0
             else if (logger.isDebugEnabled())
 2159  
             {
 2160  0
                 logger.debug("Transport '" + getProtocol() + "' will not support requests: ");
 2161  
             }
 2162  
 
 2163  0
             sessionHandler = serviceDescriptor.createSessionHandler();
 2164  
         }
 2165  0
         catch (Exception e)
 2166  
         {
 2167  0
             throw new InitialisationException(e, this);
 2168  0
         }
 2169  0
     }
 2170  
 
 2171  
     /**
 2172  
      * Get the {@link TransportServiceDescriptor} for this connector. This will be
 2173  
      * null if the connector was created by the developer. To create a connector the
 2174  
      * proper way the developer should use the {@link TransportFactory} and pass in
 2175  
      * an endpoint.
 2176  
      *
 2177  
      * @return the {@link TransportServiceDescriptor} for this connector
 2178  
      */
 2179  
     protected TransportServiceDescriptor getServiceDescriptor()
 2180  
     {
 2181  0
         if (serviceDescriptor == null)
 2182  
         {
 2183  0
             throw new IllegalStateException("This connector has not yet been initialised: " + name);
 2184  
         }
 2185  0
         return serviceDescriptor;
 2186  
     }
 2187  
 
 2188  
     /**
 2189  
      * Create a Message receiver for this connector
 2190  
      *
 2191  
      * @param flowConstruct the service that will receive events from this receiver, the
 2192  
      *                      listener
 2193  
      * @param endpoint      the endpoint that defies this inbound communication
 2194  
      * @return an instance of the message receiver defined in this connectors'
 2195  
      *         {@link org.mule.transport.service.TransportServiceDescriptor}
 2196  
      *         initialised using the service and endpoint.
 2197  
      * @throws Exception if there is a problem creating the receiver. This exception
 2198  
      *                   really depends on the underlying transport, thus any exception
 2199  
      *                   could be thrown
 2200  
      */
 2201  
     protected MessageReceiver createReceiver(FlowConstruct flowConstruct, InboundEndpoint endpoint) throws Exception
 2202  
     {
 2203  0
         return getServiceDescriptor().createMessageReceiver(this, flowConstruct, endpoint);
 2204  
     }
 2205  
 
 2206  
     /**
 2207  
      * A map of fully qualified class names that should override those in the
 2208  
      * connectors' service descriptor This map will be null if there are no overrides
 2209  
      *
 2210  
      * @return a map of override values or null
 2211  
      */
 2212  
     public Map getServiceOverrides()
 2213  
     {
 2214  0
         return serviceOverrides;
 2215  
     }
 2216  
 
 2217  
     /**
 2218  
      * Set the Service overrides on this connector.
 2219  
      *
 2220  
      * @param serviceOverrides the override values to use
 2221  
      */
 2222  
     public void setServiceOverrides(Map serviceOverrides)
 2223  
     {
 2224  0
         this.serviceOverrides = new Properties();
 2225  0
         this.serviceOverrides.putAll(serviceOverrides);
 2226  0
     }
 2227  
 
 2228  
     /**
 2229  
      * Will get the output stream for this type of transport. Typically this will be
 2230  
      * called only when Streaming is being used on an outbound endpoint. If Streaming
 2231  
      * is not supported by this transport an {@link UnsupportedOperationException} is
 2232  
      * thrown. Note that the stream MUST release resources on close. For help doing
 2233  
      * so, see {@link org.mule.model.streaming.CallbackOutputStream}.
 2234  
      *
 2235  
      * @param endpoint the endpoint that releates to this Dispatcher
 2236  
      * @param event  the current event being processed
 2237  
      * @return the output stream to use for this request
 2238  
      * @throws MuleException in case of any error
 2239  
      */
 2240  
     public OutputStream getOutputStream(OutboundEndpoint endpoint, MuleEvent event) throws MuleException
 2241  
     {
 2242  0
         throw new UnsupportedOperationException(CoreMessages.streamingNotSupported(this.getProtocol()).toString());
 2243  
     }
 2244  
 
 2245  
     public MuleContext getMuleContext()
 2246  
     {
 2247  0
         return muleContext;
 2248  
     }
 2249  
 
 2250  
     @Override
 2251  
     public String toString()
 2252  
     {
 2253  0
         final StringBuffer sb = new StringBuffer(120);
 2254  0
         final String nl = System.getProperty("line.separator");
 2255  0
         sb.append(ClassUtils.getSimpleName(this.getClass()));
 2256  
         // format message for multi-line output, single-line is not readable
 2257  0
         sb.append(nl);
 2258  0
         sb.append("{");
 2259  0
         sb.append(nl);
 2260  0
         sb.append("  name=").append(name);
 2261  0
         sb.append(nl);
 2262  0
         sb.append("  lifecycle=").append(
 2263  
                 lifecycleManager == null ? "<not in lifecycle>" : lifecycleManager.getCurrentPhase());
 2264  0
         sb.append(nl);
 2265  0
         sb.append("  this=").append(Integer.toHexString(System.identityHashCode(this)));
 2266  0
         sb.append(nl);
 2267  0
         sb.append("  numberOfConcurrentTransactedReceivers=").append(numberOfConcurrentTransactedReceivers);
 2268  0
         sb.append(nl);
 2269  0
         sb.append("  createMultipleTransactedReceivers=").append(createMultipleTransactedReceivers);
 2270  0
         sb.append(nl);
 2271  0
         sb.append("  connected=").append(connected);
 2272  0
         sb.append(nl);
 2273  0
         sb.append("  supportedProtocols=").append(supportedProtocols);
 2274  0
         sb.append(nl);
 2275  0
         sb.append("  serviceOverrides=");
 2276  0
         if (serviceOverrides != null)
 2277  
         {
 2278  0
             for (Map.Entry<Object, Object> entry : serviceOverrides.entrySet())
 2279  
             {
 2280  0
                 sb.append(nl);
 2281  0
                 sb.append("    ").append(String.format("%s=%s", entry.getKey(), entry.getValue()));
 2282  
             }
 2283  
         }
 2284  
         else
 2285  
         {
 2286  0
             sb.append("<none>");
 2287  
         }
 2288  0
         sb.append(nl);
 2289  0
         sb.append('}');
 2290  0
         sb.append(nl);
 2291  0
         return sb.toString();
 2292  
     }
 2293  
 
 2294  
     public RetryPolicyTemplate getRetryPolicyTemplate()
 2295  
     {
 2296  0
         return retryPolicyTemplate;
 2297  
     }
 2298  
 
 2299  
     public void setRetryPolicyTemplate(RetryPolicyTemplate retryPolicyTemplate)
 2300  
     {
 2301  0
         this.retryPolicyTemplate = retryPolicyTemplate;
 2302  0
     }
 2303  
 
 2304  
     /**
 2305  
      * Whether to test a connection on each take from pool.
 2306  
      */
 2307  
     public boolean isValidateConnections()
 2308  
     {
 2309  0
         return validateConnections;
 2310  
     }
 2311  
 
 2312  
     /**
 2313  
      * Whether to test a connection on each take. A result is higher availability at
 2314  
      * the expense of a potential slight performance hit (when a test connection is
 2315  
      * made) or be very lightweight in other cases (like sending a hearbeat ping to
 2316  
      * the server).
 2317  
      * <p/>
 2318  
      * Disable to obtain slight performance gain or if you are absolutely sure of the
 2319  
      * server availability.
 2320  
      * <p/>
 2321  
      * It is up to the transport implementatin to support such validation, thus it
 2322  
      * should be considered a hint only.
 2323  
      * <p/>
 2324  
      * The default value is <code>true</code>
 2325  
      */
 2326  
     public void setValidateConnections(final boolean validateConnections)
 2327  
     {
 2328  0
         this.validateConnections = validateConnections;
 2329  0
     }
 2330  
 
 2331  
     // MULE-4751 Expose some dispatcher and requester object pool configuration
 2332  
 
 2333  
     /**
 2334  
      * Allows an ExhaustedAction to be configured on the dispatcher object pool See:
 2335  
      * {@link GenericKeyedObjectPool#setWhenExhaustedAction(byte)}
 2336  
      */
 2337  
     public void setDispatcherPoolWhenExhaustedAction(byte whenExhaustedAction)
 2338  
     {
 2339  0
         checkDispatchersInitialised();
 2340  0
         dispatchers.setWhenExhaustedAction(whenExhaustedAction);
 2341  0
     }
 2342  
 
 2343  
     /**
 2344  
      * Allows a maxWait timeout to be configured on the dispatcher object pool See:
 2345  
      * {@link GenericKeyedObjectPool#setMaxWait(long)}
 2346  
      */
 2347  
     public void setDispatcherPoolMaxWait(int maxWait)
 2348  
     {
 2349  0
         checkDispatchersInitialised();
 2350  0
         dispatchers.setMaxWait(maxWait);
 2351  0
     }
 2352  
 
 2353  
     /**
 2354  
      * Allows to define a factory to create the dispatchers pool that will be used in the connector
 2355  
      */
 2356  
     public void setDispatcherPoolFactory(ConfigurableKeyedObjectPoolFactory dispatcherPoolFactory)
 2357  
     {
 2358  0
         this.dispatcherPoolFactory = dispatcherPoolFactory;
 2359  0
     }
 2360  
 
 2361  
     public ConfigurableKeyedObjectPoolFactory getDispatcherPoolFactory()
 2362  
     {
 2363  0
         return dispatcherPoolFactory;
 2364  
     }
 2365  
 
 2366  
     /**
 2367  
      * Allows an ExhaustedAction to be configured on the requester object pool See:
 2368  
      * {@link GenericKeyedObjectPool#setWhenExhaustedAction(byte)}
 2369  
      */
 2370  
     public void setRequesterPoolWhenExhaustedAction(byte whenExhaustedAction)
 2371  
     {
 2372  0
         requesters.setWhenExhaustedAction(whenExhaustedAction);
 2373  0
     }
 2374  
 
 2375  
     /**
 2376  
      * Allows a maxWait timeout to be configured on the requester object pool See:
 2377  
      * {@link GenericKeyedObjectPool#setMaxWait(long)}
 2378  
      */
 2379  
     public void setRequesterPoolMaxWait(int maxWait)
 2380  
     {
 2381  0
         requesters.setMaxWait(maxWait);
 2382  0
     }
 2383  
 
 2384  
     public MessageProcessor createDispatcherMessageProcessor(OutboundEndpoint endpoint) throws MuleException
 2385  
     {
 2386  0
         if (endpoint.getExchangePattern().hasResponse() || !getDispatcherThreadingProfile().isDoThreading())
 2387  
         {
 2388  0
             return new DispatcherMessageProcessor();
 2389  
         }
 2390  
         else
 2391  
         {
 2392  0
             DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder();
 2393  0
             builder.chain(new OptionalAsyncInterceptingMessageProcessor(new WorkManagerSource()
 2394  0
             {
 2395  
                 public WorkManager getWorkManager() throws MuleException
 2396  
                 {
 2397  0
                     return getDispatcherWorkManager();
 2398  
                 }
 2399  
             }));
 2400  0
             builder.chain(new DispatcherMessageProcessor());
 2401  0
             return builder.build();
 2402  
         }
 2403  
     }
 2404  
     
 2405  
     public MessageExchangePattern getDefaultExchangePattern()
 2406  
     {
 2407  
         try
 2408  
         {
 2409  0
             return serviceDescriptor.getDefaultExchangePattern();
 2410  
         }
 2411  0
         catch (TransportServiceException tse)
 2412  
         {
 2413  0
             throw new MuleRuntimeException(tse);
 2414  
         }
 2415  
     }
 2416  
     
 2417  
     public List<MessageExchangePattern> getInboundExchangePatterns()
 2418  
     {
 2419  
         try
 2420  
         {
 2421  0
             return serviceDescriptor.getInboundExchangePatterns();
 2422  
         }
 2423  0
         catch (TransportServiceException tse)
 2424  
         {
 2425  0
             throw new MuleRuntimeException(tse);
 2426  
         }
 2427  
     }
 2428  
 
 2429  
     public List<MessageExchangePattern> getOutboundExchangePatterns()
 2430  
     {
 2431  
         try
 2432  
         {
 2433  0
             return serviceDescriptor.getOutboundExchangePatterns();
 2434  
         }
 2435  0
         catch (TransportServiceException tse)
 2436  
         {
 2437  0
             throw new MuleRuntimeException(tse);
 2438  
         }
 2439  
     }
 2440  
     
 2441  0
     class DispatcherMessageProcessor implements MessageProcessor
 2442  
     {
 2443  
         private MessageProcessor notificationMessageProcessor;
 2444  
 
 2445  
         public MuleEvent process(MuleEvent event) throws MuleException
 2446  
         {
 2447  0
             OutboundEndpoint endpoint = (OutboundEndpoint) event.getEndpoint();
 2448  0
             MessageDispatcher dispatcher = null;
 2449  
             try
 2450  
             {
 2451  0
                 dispatcher = getDispatcher(endpoint);
 2452  0
                 MuleEvent result = dispatcher.process(event);
 2453  
                 // We need to invoke notification message processor with request
 2454  
                 // message only after successful send/dispatch
 2455  0
                 if (notificationMessageProcessor == null)
 2456  
                 {
 2457  0
                     notificationMessageProcessor = new OutboundNotificationMessageProcessor(endpoint);
 2458  
                 }
 2459  0
                 notificationMessageProcessor.process(event);
 2460  0
                 return result;
 2461  
 
 2462  
             }
 2463  0
             catch (DispatchException dex)
 2464  
             {
 2465  0
                 throw dex;
 2466  
             }
 2467  0
             catch (MuleException ex)
 2468  
             {
 2469  0
                 throw new DispatchException(event, endpoint, ex);
 2470  
             }
 2471  
             finally
 2472  
             {
 2473  0
                 returnDispatcher(endpoint, dispatcher);
 2474  
             }
 2475  
         }
 2476  
         
 2477  
         @Override
 2478  
         public String toString()
 2479  
         {
 2480  0
             return ObjectUtils.toString(this);
 2481  
         }
 2482  
     };
 2483  
 }