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