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