Coverage Report - org.mule.transport.jms.JmsConnector
 
Classes in this File Line Coverage Branch Coverage Complexity
JmsConnector
0%
0/340
0%
0/118
0
JmsConnector$1
0%
0/4
0%
0/4
0
 
 1  
 /*
 2  
  * $Id: JmsConnector.java 20501 2010-12-08 00:52:19Z tcarlson $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.transport.jms;
 12  
 
 13  
 import org.mule.api.MuleContext;
 14  
 import org.mule.api.MuleException;
 15  
 import org.mule.api.MuleRuntimeException;
 16  
 import org.mule.api.construct.FlowConstruct;
 17  
 import org.mule.api.context.notification.ConnectionNotificationListener;
 18  
 import org.mule.api.endpoint.ImmutableEndpoint;
 19  
 import org.mule.api.endpoint.InboundEndpoint;
 20  
 import org.mule.api.lifecycle.InitialisationException;
 21  
 import org.mule.api.lifecycle.StartException;
 22  
 import org.mule.api.lifecycle.StopException;
 23  
 import org.mule.api.transaction.Transaction;
 24  
 import org.mule.api.transaction.TransactionException;
 25  
 import org.mule.api.transport.ReplyToHandler;
 26  
 import org.mule.config.ExceptionHelper;
 27  
 import org.mule.config.i18n.CoreMessages;
 28  
 import org.mule.config.i18n.MessageFactory;
 29  
 import org.mule.context.notification.ConnectionNotification;
 30  
 import org.mule.context.notification.NotificationException;
 31  
 import org.mule.transaction.TransactionCoordination;
 32  
 import org.mule.transport.AbstractConnector;
 33  
 import org.mule.transport.ConnectException;
 34  
 import org.mule.transport.jms.i18n.JmsMessages;
 35  
 import org.mule.transport.jms.redelivery.AutoDiscoveryRedeliveryHandlerFactory;
 36  
 import org.mule.transport.jms.redelivery.RedeliveryHandlerFactory;
 37  
 import org.mule.transport.jms.xa.ConnectionFactoryWrapper;
 38  
 import org.mule.util.BeanUtils;
 39  
 
 40  
 import java.text.MessageFormat;
 41  
 import java.util.Hashtable;
 42  
 import java.util.Map;
 43  
 
 44  
 import javax.jms.Connection;
 45  
 import javax.jms.ConnectionFactory;
 46  
 import javax.jms.ExceptionListener;
 47  
 import javax.jms.JMSException;
 48  
 import javax.jms.MessageConsumer;
 49  
 import javax.jms.MessageProducer;
 50  
 import javax.jms.Session;
 51  
 import javax.jms.TemporaryQueue;
 52  
 import javax.jms.TemporaryTopic;
 53  
 import javax.jms.XAConnectionFactory;
 54  
 import javax.naming.CommunicationException;
 55  
 import javax.naming.Context;
 56  
 import javax.naming.InitialContext;
 57  
 import javax.naming.NamingException;
 58  
 
 59  
 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
 60  
 
 61  
 /**
 62  
  * <code>JmsConnector</code> is a JMS 1.0.2b compliant connector that can be used
 63  
  * by a Mule endpoint. The connector supports all JMS functionality including topics
 64  
  * and queues, durable subscribers, acknowledgement modes and local transactions.
 65  
  */
 66  
 
 67  0
 public class JmsConnector extends AbstractConnector implements ExceptionListener
 68  
 {
 69  
 
 70  
     public static final String JMS = "jms";
 71  
 
 72  
     /**
 73  
      * Indicates that Mule should throw an exception on any redelivery attempt.
 74  
      */
 75  
     public static final int REDELIVERY_FAIL_ON_FIRST = 0;
 76  
 
 77  
     public static final int REDELIVERY_IGNORE = -1;
 78  
 
 79  0
     private AtomicInteger receiverReportedExceptionCount = new AtomicInteger();
 80  
 
 81  
     ////////////////////////////////////////////////////////////////////////
 82  
     // Properties
 83  
     ////////////////////////////////////////////////////////////////////////
 84  
 
 85  0
     private int acknowledgementMode = Session.AUTO_ACKNOWLEDGE;
 86  
 
 87  
     private String clientId;
 88  
 
 89  
     private boolean durable;
 90  
 
 91  
     private boolean noLocal;
 92  
 
 93  
     private boolean persistentDelivery;
 94  
 
 95  
     private boolean honorQosHeaders;
 96  
 
 97  0
     private int maxRedelivery = REDELIVERY_FAIL_ON_FIRST;
 98  
 
 99  0
     private boolean cacheJmsSessions = false;
 100  
 
 101  
     /**
 102  
      * Whether to create a consumer on connect.
 103  
      */
 104  0
     private boolean eagerConsumer = true;
 105  
 
 106  
     ////////////////////////////////////////////////////////////////////////
 107  
     // JMS Connection
 108  
     ////////////////////////////////////////////////////////////////////////
 109  
 
 110  
     /**
 111  
      * JMS Connection, not settable by the user.
 112  
      */
 113  
     private Connection connection;
 114  
 
 115  
     private ConnectionFactory connectionFactory;
 116  
 
 117  
     private Map connectionFactoryProperties;
 118  
 
 119  0
     public String username = null;
 120  
 
 121  0
     public String password = null;
 122  
 
 123  
     ////////////////////////////////////////////////////////////////////////
 124  
     // JNDI Connection
 125  
     ////////////////////////////////////////////////////////////////////////
 126  
 
 127  0
     private Context jndiContext = null;
 128  
 
 129  
     /**
 130  
      * This object guards all access to the jndiContext
 131  
      */
 132  0
     private final Object jndiLock = new Object();
 133  
 
 134  
     private String jndiProviderUrl;
 135  
 
 136  
     private String jndiInitialFactory;
 137  
 
 138  
     private Map jndiProviderProperties;
 139  
 
 140  
     private String connectionFactoryJndiName;
 141  
 
 142  0
     private boolean jndiDestinations = false;
 143  
 
 144  0
     private boolean forceJndiDestinations = false;
 145  
 
 146  
     ////////////////////////////////////////////////////////////////////////
 147  
     // Strategy classes
 148  
     ////////////////////////////////////////////////////////////////////////
 149  
 
 150  0
     private String specification = JmsConstants.JMS_SPECIFICATION_102B;
 151  
 
 152  
     private JmsSupport jmsSupport;
 153  
 
 154  
     private JmsTopicResolver topicResolver;
 155  
 
 156  
     private RedeliveryHandlerFactory redeliveryHandlerFactory;
 157  
 
 158  
     /**
 159  
      * determines whether a temporary JMSReplyTo destination will be used when using synchronous outbound JMS endpoints
 160  
      */
 161  0
     private boolean disableTemporaryReplyToDestinations = false;
 162  
 
 163  
     /**
 164  
      * If disableTemporaryReplyToDestinations = "true", this flag causes the original JMS Message to be returned as a
 165  
      * synchronous response with any properties set on it by the JMS Provider (e.g., JMSMessageID).
 166  
      *
 167  
      * @see EE-1688/MULE-3059
 168  
      */
 169  0
     private boolean returnOriginalMessageAsReply = false;
 170  
 
 171  
     /**
 172  
      * In-container embedded mode disables some features for strict Java EE compliance.
 173  
      */
 174  
     private boolean embeddedMode;
 175  
 
 176  
     /**
 177  
      * Overrides XaResource.isSameRM() result. Needed for IBM WMQ XA
 178  
      * implementation (set to 'false'). Default value is null (don't override).
 179  
      */
 180  
     private Boolean sameRMOverrideValue;
 181  
 
 182  
     ////////////////////////////////////////////////////////////////////////
 183  
     // Methods
 184  
     ////////////////////////////////////////////////////////////////////////
 185  
 
 186  
     /* Register the Jms Exception reader if this class gets loaded */
 187  
 
 188  
     static
 189  
     {
 190  0
         ExceptionHelper.registerExceptionReader(new JmsExceptionReader());
 191  0
     }
 192  
 
 193  
     public JmsConnector(MuleContext context)
 194  
     {
 195  0
         super(context);
 196  0
     }
 197  
     
 198  
     public String getProtocol()
 199  
     {
 200  0
         return JMS;
 201  
     }
 202  
 
 203  
     @Override
 204  
     protected void doInitialise() throws InitialisationException
 205  
     {        
 206  
         try
 207  
         {
 208  0
             connectionFactory = this.createConnectionFactory();
 209  
         }
 210  0
         catch (NamingException ne)
 211  
         {
 212  0
             throw new InitialisationException(JmsMessages.errorCreatingConnectionFactory(), ne, this);
 213  0
         }
 214  
 
 215  0
         if ((connectionFactoryProperties != null) && !connectionFactoryProperties.isEmpty())
 216  
         {
 217  
             // apply connection factory properties
 218  0
             BeanUtils.populateWithoutFail(connectionFactory, connectionFactoryProperties, true);
 219  
         }
 220  
 
 221  0
         if (topicResolver == null)
 222  
         {
 223  0
             topicResolver = new DefaultJmsTopicResolver(this);
 224  
         }
 225  0
         if (redeliveryHandlerFactory == null)
 226  
         {
 227  0
             redeliveryHandlerFactory = new AutoDiscoveryRedeliveryHandlerFactory(this);
 228  
         }
 229  
 
 230  
         try
 231  
         {
 232  0
             muleContext.registerListener(new ConnectionNotificationListener<ConnectionNotification>()
 233  0
             {
 234  
                 public void onNotification(ConnectionNotification notification)
 235  
                 {
 236  0
                     if (notification.getAction() == ConnectionNotification.CONNECTION_DISCONNECTED
 237  
                             || notification.getAction() == ConnectionNotification.CONNECTION_FAILED)
 238  
                     {
 239  
                         // Remove all dispatchers as any cached session will be invalidated
 240  0
                         clearDispatchers();
 241  
                         // TODO should we dispose receivers here as well (in case they are
 242  
                         // transactional)
 243  
                         // gives a harmless NPE at
 244  
                         // AbstractConnector.connect(AbstractConnector.java:927)
 245  
                         // disposeReceivers();
 246  
                     }
 247  0
                 }
 248  
 
 249  
             }, getName());
 250  
 
 251  
 
 252  
         }
 253  0
         catch (NotificationException nex)
 254  
         {
 255  0
             throw new InitialisationException(nex, this);
 256  0
         }
 257  
 
 258  0
         if (jmsSupport == null)
 259  
         {
 260  0
             jmsSupport = createJmsSupport();
 261  
         }
 262  0
     }
 263  
 
 264  
     /**
 265  
      * A factory method to create various JmsSupport class versions.
 266  
      *
 267  
      * @return JmsSupport instance
 268  
      * @see JmsSupport
 269  
      */
 270  
     protected JmsSupport createJmsSupport()
 271  
     {
 272  
         final JmsSupport result;
 273  0
         if (JmsConstants.JMS_SPECIFICATION_102B.equals(specification))
 274  
         {
 275  0
             result = new Jms102bSupport(this);
 276  
         }
 277  
         else
 278  
         {
 279  0
             result = new Jms11Support(this);
 280  
         }
 281  
 
 282  0
         return result;
 283  
     }
 284  
 
 285  
     protected ConnectionFactory createConnectionFactory() throws InitialisationException, NamingException
 286  
     {
 287  
         // if an initial factory class was configured that takes precedence over the 
 288  
         // spring-configured connection factory or the one that our subclasses may provide
 289  0
         if (jndiInitialFactory != null)
 290  
         {
 291  0
             this.initJndiContext();
 292  
 
 293  0
             Object temp = jndiContext.lookup(connectionFactoryJndiName);
 294  0
             if (temp instanceof ConnectionFactory)
 295  
             {
 296  0
                 return (ConnectionFactory) temp;
 297  
             }
 298  
             else
 299  
             {
 300  0
                 throw new InitialisationException(
 301  
                         JmsMessages.invalidResourceType(ConnectionFactory.class, temp), this);
 302  
             }
 303  
         }
 304  
         else
 305  
         {
 306  
             // don't look up objects from JNDI in any case
 307  0
             jndiDestinations = false;
 308  0
             forceJndiDestinations = false;
 309  
 
 310  
             // don't use JNDI. Use the spring-configured connection factory if that's provided
 311  0
             if (connectionFactory != null)
 312  
             {
 313  0
                 return connectionFactory;
 314  
             }
 315  
 
 316  
             // no spring-configured connection factory. See if there is a default one (e.g. from
 317  
             // subclass)
 318  
             ConnectionFactory factory;
 319  
             try
 320  
             {
 321  0
                 factory = getDefaultConnectionFactory();
 322  
             }
 323  0
             catch (Exception e)
 324  
             {
 325  0
                 throw new InitialisationException(e, this);
 326  0
             }
 327  0
             if (factory == null)
 328  
             {
 329  
                 // no connection factory ... give up
 330  0
                 throw new InitialisationException(JmsMessages.noConnectionFactoryConfigured(), this);
 331  
             }
 332  0
             return factory;
 333  
         }
 334  
     }
 335  
 
 336  
     /**
 337  
      * Override this method to provide a default ConnectionFactory for a vendor-specific JMS Connector.
 338  
      * @throws Exception 
 339  
      */
 340  
     protected ConnectionFactory getDefaultConnectionFactory() throws Exception
 341  
     {
 342  0
         return null;
 343  
     }
 344  
 
 345  
     @Override
 346  
     protected void doDispose()
 347  
     {
 348  0
         if (connection != null)
 349  
         {
 350  
             try
 351  
             {
 352  0
                 connection.close();
 353  
             }
 354  0
             catch (JMSException e)
 355  
             {
 356  0
                 logger.error("Jms connector failed to dispose properly: ", e);
 357  0
             }
 358  0
             connection = null;
 359  
         }
 360  
 
 361  0
         if (jndiContext != null)
 362  
         {
 363  
             try
 364  
             {
 365  0
                 jndiContext.close();
 366  
             }
 367  0
             catch (NamingException ne)
 368  
             {
 369  0
                 logger.error("Jms connector failed to dispose properly: ", ne);
 370  
             }
 371  
             finally
 372  
             {
 373  0
                 jndiContext = null;
 374  0
             }
 375  
         }
 376  0
     }
 377  
 
 378  
     protected void initJndiContext() throws NamingException, InitialisationException
 379  
     {
 380  0
         synchronized (jndiLock)
 381  
         {
 382  0
             Hashtable<String, Object> props = new Hashtable<String, Object>();
 383  
 
 384  0
             if (jndiInitialFactory != null)
 385  
             {
 386  0
                 props.put(Context.INITIAL_CONTEXT_FACTORY, jndiInitialFactory);
 387  
             }
 388  0
             else if (jndiProviderProperties == null
 389  
                     || !jndiProviderProperties.containsKey(Context.INITIAL_CONTEXT_FACTORY))
 390  
             {
 391  0
                 throw new InitialisationException(CoreMessages.objectIsNull("jndiInitialFactory"), this);
 392  
             }
 393  
 
 394  0
             if (jndiProviderUrl != null)
 395  
             {
 396  0
                 props.put(Context.PROVIDER_URL, jndiProviderUrl);
 397  
             }
 398  
 
 399  0
             if (jndiProviderProperties != null)
 400  
             {
 401  0
                 props.putAll(jndiProviderProperties);
 402  
             }
 403  
 
 404  0
             jndiContext = new InitialContext(props);
 405  0
         }
 406  0
     }
 407  
 
 408  
     protected Object lookupFromJndi(String jndiName) throws NamingException
 409  
     {
 410  0
         synchronized (jndiLock)
 411  
         {
 412  
             try
 413  
             {
 414  0
                 return jndiContext.lookup(jndiName);
 415  
             }
 416  0
             catch (CommunicationException ce)
 417  
             {
 418  
                 try
 419  
                 {
 420  0
                     final Transaction tx = TransactionCoordination.getInstance().getTransaction();
 421  0
                     if (tx != null)
 422  
                     {
 423  0
                         tx.setRollbackOnly();
 424  
                     }
 425  
                 }
 426  0
                 catch (TransactionException e)
 427  
                 {
 428  0
                     throw new MuleRuntimeException(
 429  
                             MessageFactory.createStaticMessage("Failed to mark transaction for rollback: "), e);
 430  0
                 }
 431  
 
 432  
                 // re-throw
 433  0
                 throw ce;
 434  
             }
 435  0
         }
 436  
     }
 437  
 
 438  
     protected Connection createConnection() throws NamingException, JMSException, InitialisationException
 439  
     {
 440  0
         ConnectionFactory cf = this.connectionFactory;
 441  
         Connection connection;
 442  
 
 443  
         try
 444  
         {
 445  0
             if (cf instanceof XAConnectionFactory && muleContext.getTransactionManager() != null)
 446  
             {
 447  0
                 cf = new ConnectionFactoryWrapper(cf, sameRMOverrideValue);
 448  
             }
 449  
         }
 450  0
         catch (Exception e)
 451  
         {
 452  0
             throw new InitialisationException(e, this);
 453  0
         }
 454  
 
 455  0
         if (username != null)
 456  
         {
 457  0
             connection = jmsSupport.createConnection(cf, username, password);
 458  
         }
 459  
         else
 460  
         {
 461  0
             connection = jmsSupport.createConnection(cf);
 462  
         }
 463  
 
 464  0
         if (connection != null)
 465  
         {
 466  
             // EE-1901: only sets the clientID if it was not already set
 467  0
             if (clientId != null && !clientId.equals(connection.getClientID()))
 468  
             {
 469  0
                 connection.setClientID(getClientId());
 470  
             }
 471  0
             if (!embeddedMode)
 472  
             {
 473  0
                 connection.setExceptionListener(this);
 474  
             }
 475  
         }
 476  
 
 477  
 
 478  0
         return connection;
 479  
     }
 480  
 
 481  
     public void onException(JMSException jmsException)
 482  
     {
 483  0
         final JmsConnector jmsConnector = JmsConnector.this;
 484  0
         Map receivers = jmsConnector.getReceivers();
 485  0
         boolean isMultiConsumerReceiver = false;
 486  
 
 487  0
         if (!receivers.isEmpty())
 488  
         {
 489  0
             Map.Entry entry = (Map.Entry) receivers.entrySet().iterator().next();
 490  0
             if (entry.getValue() instanceof MultiConsumerJmsMessageReceiver)
 491  
             {
 492  0
                 isMultiConsumerReceiver = true;
 493  
             }
 494  
         }
 495  
 
 496  0
         int expectedReceiverCount = isMultiConsumerReceiver ? 1 :
 497  
                 (jmsConnector.getReceivers().size() * jmsConnector.getNumberOfConcurrentTransactedReceivers());
 498  
 
 499  0
         if (logger.isDebugEnabled())
 500  
         {
 501  0
             logger.debug("About to recycle myself due to remote JMS connection shutdown but need "
 502  
                     + "to wait for all active receivers to report connection loss. Receiver count: "
 503  
                     + (receiverReportedExceptionCount.get() + 1) + '/' + expectedReceiverCount);
 504  
         }
 505  
 
 506  0
         if (receiverReportedExceptionCount.incrementAndGet() >= expectedReceiverCount)
 507  
         {
 508  0
             receiverReportedExceptionCount.set(0);
 509  
 
 510  0
             handleException(new ConnectException(jmsException, this));
 511  
         }
 512  0
     }
 513  
 
 514  
     // TODO This might make retry work a bit better w/ JMS
 515  
 //    @Override
 516  
 //    public boolean validateConnection() throws Exception
 517  
 //    {
 518  
 //        logger.debug("Creating a temporary session to verify that we have a healthy connection...");
 519  
 //
 520  
 //        Connection connection;
 521  
 //        Session session;
 522  
 //        try
 523  
 //        {
 524  
 //            connection = createConnection();
 525  
 //            if (connection == null)
 526  
 //            {
 527  
 //                return false;
 528  
 //            }
 529  
 //            session = connection.createSession(false, 1);
 530  
 //            if (session == null)
 531  
 //            {
 532  
 //                return false;
 533  
 //            }
 534  
 //            session.close();
 535  
 //            connection.close();
 536  
 //            return true;
 537  
 //        }
 538  
 //        finally
 539  
 //        {
 540  
 //            session = null;
 541  
 //            connection = null;
 542  
 //        }
 543  
 //    }
 544  
 
 545  
     @Override
 546  
     protected void doConnect() throws Exception
 547  
     {
 548  0
         connection = createConnection();
 549  0
         if (isStarted())
 550  
         {
 551  0
             connection.start();
 552  
         }
 553  0
     }
 554  
 
 555  
     @Override
 556  
     protected void doDisconnect() throws Exception
 557  
     {
 558  
         try
 559  
         {
 560  0
             if (connection != null)
 561  
             {
 562  
                 // Ignore exceptions while closing the connection
 563  0
                 if (!embeddedMode)
 564  
                 {
 565  0
                     connection.setExceptionListener(null);
 566  
                 }
 567  0
                 connection.close();
 568  
             }
 569  
         }
 570  
         finally
 571  
         {
 572  
             // connectionFactory = null;
 573  0
             connection = null;
 574  0
         }
 575  0
     }
 576  
 
 577  
     @Override
 578  
     protected Object getReceiverKey(FlowConstruct flowConstruct, InboundEndpoint endpoint)
 579  
     {
 580  0
         return flowConstruct.getName() + "~" + endpoint.getEndpointURI().getAddress();
 581  
     }
 582  
 
 583  
     public Session getSessionFromTransaction()
 584  
     {
 585  0
         Transaction tx = TransactionCoordination.getInstance().getTransaction();
 586  0
         if (tx != null)
 587  
         {
 588  0
             if (tx.hasResource(connection))
 589  
             {
 590  0
                 if (logger.isDebugEnabled())
 591  
                 {
 592  0
                     logger.debug("Retrieving jms session from current transaction " + tx);
 593  
                 }
 594  
 
 595  0
                 Session session = (Session) tx.getResource(connection);
 596  
 
 597  0
                 if (logger.isDebugEnabled())
 598  
                 {
 599  0
                     logger.debug("Using " + session + " bound to transaction " + tx);
 600  
                 }
 601  
 
 602  0
                 return session;
 603  
             }
 604  
         }
 605  0
         return null;
 606  
     }
 607  
 
 608  
     public Session getSession(ImmutableEndpoint endpoint) throws JMSException
 609  
     {
 610  0
         final boolean topic = getTopicResolver().isTopic(endpoint);
 611  0
         return getSession(endpoint.getTransactionConfig().isTransacted(), topic);
 612  
     }
 613  
 
 614  
     public Session getSession(boolean transacted, boolean topic) throws JMSException
 615  
     {
 616  0
         Session session = getSessionFromTransaction();
 617  0
         if (session != null)
 618  
         {
 619  0
             return session;
 620  
         }
 621  
 
 622  0
         Transaction tx = TransactionCoordination.getInstance().getTransaction();
 623  
 
 624  0
         session = jmsSupport.createSession(connection, topic, transacted, acknowledgementMode, noLocal);
 625  
 
 626  0
         if (logger.isDebugEnabled())
 627  
         {
 628  0
             logger.debug(MessageFormat.format(
 629  
                     "Retrieved new jms session from connection: " +
 630  
                             "topic={0}, transacted={1}, ack mode={2}, nolocal={3}: {4}",
 631  
                     topic, transacted, acknowledgementMode, noLocal, session));
 632  
         }
 633  
 
 634  0
         if (tx != null)
 635  
         {
 636  0
             logger.debug("Binding session " + session + " to current transaction " + tx);
 637  
             try
 638  
             {
 639  0
                 tx.bindResource(connection, session);
 640  
             }
 641  0
             catch (TransactionException e)
 642  
             {
 643  0
                 closeQuietly(session);
 644  0
                 throw new RuntimeException("Could not bind session to current transaction", e);
 645  0
             }
 646  
         }
 647  0
         return session;
 648  
     }
 649  
 
 650  
     @Override
 651  
     protected void doStart() throws MuleException
 652  
     {
 653  
         //TODO: This should never be null or an exception should be thrown
 654  0
         if (connection != null)
 655  
         {
 656  
             try
 657  
             {
 658  0
                 connection.start();
 659  
             }
 660  0
             catch (JMSException e)
 661  
             {
 662  0
                 throw new StartException(CoreMessages.failedToStart("Jms Connection"), e, this);
 663  0
             }
 664  
         }
 665  0
     }
 666  
 
 667  
 
 668  
     /**
 669  
      * Closes a session if there is no active transaction in the current thread, otherwise the
 670  
      * session will continue active until there is a direct call to close it.
 671  
      *
 672  
      * @param session the session that ill be closed if there is an active transaction.
 673  
      */
 674  
     public void closeSessionIfNoTransactionActive(Session session)
 675  
     {
 676  0
         final Transaction transaction = TransactionCoordination.getInstance().getTransaction();
 677  0
         if (transaction == null)
 678  
         {
 679  0
             if (logger.isDebugEnabled())
 680  
             {
 681  0
                 logger.error("Closing non-TX session: " + session);
 682  
             }
 683  0
             closeQuietly(session);
 684  
         }
 685  0
         else if (logger.isDebugEnabled())
 686  
         {
 687  0
             logger.error("Not closing TX session: " + session);
 688  
         }
 689  0
     }
 690  
 
 691  
     @Override
 692  
     protected void doStop() throws MuleException
 693  
     {
 694  0
         if (connection != null)
 695  
         {
 696  
             try
 697  
             {
 698  0
                 connection.stop();
 699  
             }
 700  0
             catch (JMSException e)
 701  
             {
 702  0
                 throw new StopException(CoreMessages.failedToStop("Jms Connection"), e, this);
 703  0
             }
 704  
         }
 705  0
     }
 706  
 
 707  
     @Override
 708  
     public ReplyToHandler getReplyToHandler(ImmutableEndpoint endpoint)
 709  
     {
 710  0
         return new JmsReplyToHandler(this, getDefaultResponseTransformers(endpoint));
 711  
     }
 712  
 
 713  
     /**
 714  
      * This method may be overridden in case a certain JMS implementation does not
 715  
      * support all the standard JMS properties.
 716  
      */
 717  
     public boolean supportsProperty(String property)
 718  
     {
 719  0
         return true;
 720  
     }
 721  
 
 722  
     /**
 723  
      * This method may be overridden in order to apply pre-processing to the message
 724  
      * as soon as it arrives.
 725  
      *
 726  
      * @param message - the incoming message
 727  
      * @param session - the JMS session
 728  
      * @return the preprocessed message
 729  
      */
 730  
     public javax.jms.Message preProcessMessage(javax.jms.Message message, Session session) throws Exception
 731  
     {
 732  0
         return message;
 733  
     }
 734  
 
 735  
     /**
 736  
      * Closes the MessageProducer
 737  
      *
 738  
      * @param producer
 739  
      * @throws JMSException
 740  
      */
 741  
     public void close(MessageProducer producer) throws JMSException
 742  
     {
 743  0
         if (producer != null)
 744  
         {
 745  0
             if (logger.isDebugEnabled())
 746  
             {
 747  0
                 logger.debug("Closing producer: " + producer);
 748  
             }
 749  0
             producer.close();
 750  
         }
 751  0
         else if (logger.isDebugEnabled())
 752  
         {
 753  0
             logger.debug("Producer is null, nothing to close");
 754  
         }
 755  0
     }
 756  
 
 757  
     /**
 758  
      * Closes the MessageProducer without throwing an exception (an error message is
 759  
      * logged instead).
 760  
      *
 761  
      * @param producer
 762  
      */
 763  
     public void closeQuietly(MessageProducer producer)
 764  
     {
 765  
         try
 766  
         {
 767  0
             close(producer);
 768  
         }
 769  0
         catch (JMSException e)
 770  
         {
 771  0
             logger.error("Failed to close jms message producer", e);
 772  0
         }
 773  0
     }
 774  
 
 775  
     /**
 776  
      * Closes the MessageConsumer
 777  
      *
 778  
      * @param consumer
 779  
      * @throws JMSException
 780  
      */
 781  
     public void close(MessageConsumer consumer) throws JMSException
 782  
     {
 783  0
         if (consumer != null)
 784  
         {
 785  0
             if (logger.isDebugEnabled())
 786  
             {
 787  0
                 logger.debug("Closing consumer: " + consumer);
 788  
             }
 789  0
             consumer.close();
 790  
         }
 791  0
         else if (logger.isDebugEnabled())
 792  
         {
 793  0
             logger.debug("Consumer is null, nothing to close");
 794  
         }
 795  0
     }
 796  
 
 797  
     /**
 798  
      * Closes the MessageConsumer without throwing an exception (an error message is
 799  
      * logged instead).
 800  
      *
 801  
      * @param consumer
 802  
      */
 803  
     public void closeQuietly(MessageConsumer consumer)
 804  
     {
 805  
         try
 806  
         {
 807  0
             close(consumer);
 808  
         }
 809  0
         catch (JMSException e)
 810  
         {
 811  0
             logger.error("Failed to close jms message consumer", e);
 812  0
         }
 813  0
     }
 814  
 
 815  
     /**
 816  
      * Closes the MuleSession
 817  
      *
 818  
      * @param session
 819  
      * @throws JMSException
 820  
      */
 821  
     public void close(Session session) throws JMSException
 822  
     {
 823  0
         if (session != null)
 824  
         {
 825  0
             if (logger.isDebugEnabled())
 826  
             {
 827  0
                 logger.debug("Closing session " + session);
 828  
             }
 829  0
             session.close();
 830  
         }
 831  0
     }
 832  
 
 833  
     /**
 834  
      * Closes the MuleSession without throwing an exception (an error message is logged
 835  
      * instead).
 836  
      *
 837  
      * @param session
 838  
      */
 839  
     public void closeQuietly(Session session)
 840  
     {
 841  
         try
 842  
         {
 843  0
             close(session);
 844  
         }
 845  0
         catch (JMSException e)
 846  
         {
 847  0
             logger.warn("Failed to close jms session consumer", e);
 848  0
         }
 849  0
     }
 850  
 
 851  
     /**
 852  
      * Closes the TemporaryQueue
 853  
      *
 854  
      * @param tempQueue
 855  
      * @throws JMSException
 856  
      */
 857  
     public void close(TemporaryQueue tempQueue) throws JMSException
 858  
     {
 859  0
         if (tempQueue != null)
 860  
         {
 861  0
             tempQueue.delete();
 862  
         }
 863  0
     }
 864  
 
 865  
     /**
 866  
      * Closes the TemporaryQueue without throwing an exception (an error message is
 867  
      * logged instead).
 868  
      *
 869  
      * @param tempQueue
 870  
      */
 871  
     public void closeQuietly(TemporaryQueue tempQueue)
 872  
     {
 873  
         try
 874  
         {
 875  0
             close(tempQueue);
 876  
         }
 877  0
         catch (JMSException e)
 878  
         {
 879  0
             if (logger.isWarnEnabled())
 880  
             {
 881  0
                 String queueName = "";
 882  
                 try
 883  
                 {
 884  0
                     queueName = tempQueue.getQueueName();
 885  
                 }
 886  0
                 catch (JMSException innerEx)
 887  
                 {
 888  
                     // ignore, we are just trying to get the queue name
 889  0
                 }
 890  0
                 logger.warn(MessageFormat.format(
 891  
                         "Failed to delete a temporary queue ''{0}'' Reason: {1}",
 892  
                         queueName, e.getMessage()));
 893  
             }
 894  0
         }
 895  0
     }
 896  
 
 897  
     /**
 898  
      * Closes the TemporaryTopic
 899  
      *
 900  
      * @param tempTopic
 901  
      * @throws JMSException
 902  
      */
 903  
     public void close(TemporaryTopic tempTopic) throws JMSException
 904  
     {
 905  0
         if (tempTopic != null)
 906  
         {
 907  0
             tempTopic.delete();
 908  
         }
 909  0
     }
 910  
 
 911  
     /**
 912  
      * Closes the TemporaryTopic without throwing an exception (an error message is
 913  
      * logged instead).
 914  
      *
 915  
      * @param tempTopic
 916  
      */
 917  
     public void closeQuietly(TemporaryTopic tempTopic)
 918  
     {
 919  
         try
 920  
         {
 921  0
             close(tempTopic);
 922  
         }
 923  0
         catch (JMSException e)
 924  
         {
 925  0
             if (logger.isWarnEnabled())
 926  
             {
 927  0
                 String topicName = "";
 928  
                 try
 929  
                 {
 930  0
                     topicName = tempTopic.getTopicName();
 931  
                 }
 932  0
                 catch (JMSException innerEx)
 933  
                 {
 934  
                     // ignore, we are just trying to get the topic name
 935  0
                 }
 936  0
                 logger.warn("Failed to delete a temporary topic " + topicName, e);
 937  
             }
 938  0
         }
 939  0
     }
 940  
 
 941  
     ////////////////////////////////////////////////////////////////////////
 942  
     // Getters and Setters
 943  
     ////////////////////////////////////////////////////////////////////////
 944  
 
 945  
     /**
 946  
      * @return Returns the connection.
 947  
      */
 948  
     public Connection getConnection()
 949  
     {
 950  0
         return connection;
 951  
     }
 952  
 
 953  
     protected void setConnection(Connection connection)
 954  
     {
 955  0
         this.connection = connection;
 956  0
     }
 957  
 
 958  
     /**
 959  
      * @return Returns the acknowledgeMode.
 960  
      */
 961  
     public int getAcknowledgementMode()
 962  
     {
 963  0
         return acknowledgementMode;
 964  
     }
 965  
 
 966  
     /**
 967  
      * @param acknowledgementMode The acknowledgementMode to set.
 968  
      */
 969  
     public void setAcknowledgementMode(int acknowledgementMode)
 970  
     {
 971  0
         this.acknowledgementMode = acknowledgementMode;
 972  0
     }
 973  
 
 974  
     /**
 975  
      * @return Returns the durable.
 976  
      */
 977  
     public boolean isDurable()
 978  
     {
 979  0
         return durable;
 980  
     }
 981  
 
 982  
     /**
 983  
      * @param durable The durable to set.
 984  
      */
 985  
     public void setDurable(boolean durable)
 986  
     {
 987  0
         this.durable = durable;
 988  0
     }
 989  
 
 990  
     /**
 991  
      * @return Returns the noLocal.
 992  
      */
 993  
     public boolean isNoLocal()
 994  
     {
 995  0
         return noLocal;
 996  
     }
 997  
 
 998  
     /**
 999  
      * @param noLocal The noLocal to set.
 1000  
      */
 1001  
     public void setNoLocal(boolean noLocal)
 1002  
     {
 1003  0
         this.noLocal = noLocal;
 1004  0
     }
 1005  
 
 1006  
     /**
 1007  
      * @return Returns the persistentDelivery.
 1008  
      */
 1009  
     public boolean isPersistentDelivery()
 1010  
     {
 1011  0
         return persistentDelivery;
 1012  
     }
 1013  
 
 1014  
     /**
 1015  
      * @param persistentDelivery The persistentDelivery to set.
 1016  
      */
 1017  
     public void setPersistentDelivery(boolean persistentDelivery)
 1018  
     {
 1019  0
         this.persistentDelivery = persistentDelivery;
 1020  0
     }
 1021  
 
 1022  
     public JmsSupport getJmsSupport()
 1023  
     {
 1024  0
         return jmsSupport;
 1025  
     }
 1026  
 
 1027  
     public void setJmsSupport(JmsSupport jmsSupport)
 1028  
     {
 1029  0
         this.jmsSupport = jmsSupport;
 1030  0
     }
 1031  
 
 1032  
     public String getSpecification()
 1033  
     {
 1034  0
         return specification;
 1035  
     }
 1036  
 
 1037  
     public void setSpecification(String specification)
 1038  
     {
 1039  0
         if (JmsConstants.JMS_SPECIFICATION_11.equals(specification)
 1040  
             || (JmsConstants.JMS_SPECIFICATION_102B.equals(specification)))
 1041  
         {
 1042  0
             this.specification = specification;
 1043  
         }
 1044  
         else
 1045  
         {
 1046  0
             throw new IllegalArgumentException(
 1047  
                 "JMS specification needs to be one of the defined values in JmsConstants but was: "
 1048  
                                 + specification);
 1049  
         }
 1050  0
     }
 1051  
 
 1052  
     public String getUsername()
 1053  
     {
 1054  0
         return username;
 1055  
     }
 1056  
 
 1057  
     public void setUsername(String username)
 1058  
     {
 1059  0
         this.username = username;
 1060  0
     }
 1061  
 
 1062  
     public String getPassword()
 1063  
     {
 1064  0
         return password;
 1065  
     }
 1066  
 
 1067  
     public void setPassword(String password)
 1068  
     {
 1069  0
         this.password = password;
 1070  0
     }
 1071  
 
 1072  
     public String getClientId()
 1073  
     {
 1074  0
         return clientId;
 1075  
     }
 1076  
 
 1077  
     public void setClientId(String clientId)
 1078  
     {
 1079  0
         this.clientId = clientId;
 1080  0
     }
 1081  
 
 1082  
     public int getMaxRedelivery()
 1083  
     {
 1084  0
         return maxRedelivery;
 1085  
     }
 1086  
 
 1087  
     public void setMaxRedelivery(int maxRedelivery)
 1088  
     {
 1089  0
         this.maxRedelivery = maxRedelivery;
 1090  0
     }
 1091  
 
 1092  
     @Override
 1093  
     public boolean isResponseEnabled()
 1094  
     {
 1095  0
         return true;
 1096  
     }
 1097  
 
 1098  
 
 1099  
     /**
 1100  
      * Getter for property 'topicResolver'.
 1101  
      *
 1102  
      * @return Value for property 'topicResolver'.
 1103  
      */
 1104  
     public JmsTopicResolver getTopicResolver()
 1105  
     {
 1106  0
         return topicResolver;
 1107  
     }
 1108  
 
 1109  
     /**
 1110  
      * Setter for property 'topicResolver'.
 1111  
      *
 1112  
      * @param topicResolver Value to set for property 'topicResolver'.
 1113  
      */
 1114  
     public void setTopicResolver(final JmsTopicResolver topicResolver)
 1115  
     {
 1116  0
         this.topicResolver = topicResolver;
 1117  0
     }
 1118  
 
 1119  
     /**
 1120  
      * Getter for property 'eagerConsumer'. Default
 1121  
      * is {@code true}.
 1122  
      *
 1123  
      * @return Value for property 'eagerConsumer'.
 1124  
      * @see #eagerConsumer
 1125  
      */
 1126  
     public boolean isEagerConsumer()
 1127  
     {
 1128  0
         return eagerConsumer;
 1129  
     }
 1130  
 
 1131  
     /**
 1132  
      * A value of {@code true} will create a consumer on
 1133  
      * connect, in contrast to lazy instantiation in the poll loop.
 1134  
      * This setting very much depends on the JMS vendor.
 1135  
      * Affects transactional receivers, typical symptoms are:
 1136  
      * <ul>
 1137  
      * <li> consumer thread hanging forever, though a message is
 1138  
      * available
 1139  
      * <li>failure to consume the first message (the rest
 1140  
      * are fine)
 1141  
      * </ul>
 1142  
      * <p/>
 1143  
      *
 1144  
      * @param eagerConsumer Value to set for property 'eagerConsumer'.
 1145  
      * @see #eagerConsumer
 1146  
      * @see org.mule.transport.jms.XaTransactedJmsMessageReceiver
 1147  
      */
 1148  
     public void setEagerConsumer(final boolean eagerConsumer)
 1149  
     {
 1150  0
         this.eagerConsumer = eagerConsumer;
 1151  0
     }
 1152  
 
 1153  
     public boolean isCacheJmsSessions()
 1154  
     {
 1155  0
         return cacheJmsSessions;
 1156  
     }
 1157  
 
 1158  
     public void setCacheJmsSessions(boolean cacheJmsSessions)
 1159  
     {
 1160  0
         this.cacheJmsSessions = cacheJmsSessions;
 1161  0
     }
 1162  
 
 1163  
     public ConnectionFactory getConnectionFactory()
 1164  
     {
 1165  0
         return connectionFactory;
 1166  
     }
 1167  
 
 1168  
     public void setConnectionFactory(ConnectionFactory connectionFactory)
 1169  
     {
 1170  0
         this.connectionFactory = connectionFactory;
 1171  0
     }
 1172  
 
 1173  
     public RedeliveryHandlerFactory getRedeliveryHandlerFactory()
 1174  
     {
 1175  0
         return redeliveryHandlerFactory;
 1176  
     }
 1177  
 
 1178  
     public void setRedeliveryHandlerFactory(RedeliveryHandlerFactory redeliveryHandlerFactory)
 1179  
     {
 1180  0
         this.redeliveryHandlerFactory = redeliveryHandlerFactory;
 1181  0
     }
 1182  
 
 1183  
     /**
 1184  
      * Sets the <code>honorQosHeaders</code> property, which determines whether
 1185  
      * {@link JmsMessageDispatcher} should honor incoming message's QoS headers
 1186  
      * (JMSPriority, JMSDeliveryMode).
 1187  
      *
 1188  
      * @param honorQosHeaders <code>true</code> if {@link JmsMessageDispatcher}
 1189  
      *                        should honor incoming message's QoS headers; otherwise
 1190  
      *                        <code>false</code> Default is <code>false</code>, meaning that
 1191  
      *                        connector settings will override message headers.
 1192  
      */
 1193  
     public void setHonorQosHeaders(boolean honorQosHeaders)
 1194  
     {
 1195  0
         this.honorQosHeaders = honorQosHeaders;
 1196  0
     }
 1197  
 
 1198  
     /**
 1199  
      * Gets the value of <code>honorQosHeaders</code> property.
 1200  
      *
 1201  
      * @return <code>true</code> if <code>JmsMessageDispatcher</code> should
 1202  
      *         honor incoming message's QoS headers; otherwise <code>false</code>
 1203  
      *         Default is <code>false</code>, meaning that connector settings will
 1204  
      *         override message headers.
 1205  
      */
 1206  
     public boolean isHonorQosHeaders()
 1207  
     {
 1208  0
         return honorQosHeaders;
 1209  
     }
 1210  
 
 1211  
     public Context getJndiContext()
 1212  
     {
 1213  0
         return jndiContext;
 1214  
     }
 1215  
 
 1216  
     public void setJndiContext(Context jndiContext)
 1217  
     {
 1218  0
         this.jndiContext = jndiContext;
 1219  0
     }
 1220  
 
 1221  
     public String getJndiInitialFactory()
 1222  
     {
 1223  0
         return jndiInitialFactory;
 1224  
     }
 1225  
 
 1226  
     public void setJndiInitialFactory(String jndiInitialFactory)
 1227  
     {
 1228  0
         this.jndiInitialFactory = jndiInitialFactory;
 1229  0
     }
 1230  
 
 1231  
     public String getJndiProviderUrl()
 1232  
     {
 1233  0
         return jndiProviderUrl;
 1234  
     }
 1235  
 
 1236  
     public void setJndiProviderUrl(String jndiProviderUrl)
 1237  
     {
 1238  0
         this.jndiProviderUrl = jndiProviderUrl;
 1239  0
     }
 1240  
 
 1241  
     public Map getJndiProviderProperties()
 1242  
     {
 1243  0
         return jndiProviderProperties;
 1244  
     }
 1245  
 
 1246  
     public void setJndiProviderProperties(Map jndiProviderProperties)
 1247  
     {
 1248  0
         this.jndiProviderProperties = jndiProviderProperties;
 1249  0
     }
 1250  
 
 1251  
     public String getConnectionFactoryJndiName()
 1252  
     {
 1253  0
         return connectionFactoryJndiName;
 1254  
     }
 1255  
 
 1256  
     public void setConnectionFactoryJndiName(String connectionFactoryJndiName)
 1257  
     {
 1258  0
         this.connectionFactoryJndiName = connectionFactoryJndiName;
 1259  0
     }
 1260  
 
 1261  
     public boolean isJndiDestinations()
 1262  
     {
 1263  0
         return jndiDestinations;
 1264  
     }
 1265  
 
 1266  
     public void setJndiDestinations(boolean jndiDestinations)
 1267  
     {
 1268  0
         this.jndiDestinations = jndiDestinations;
 1269  0
     }
 1270  
 
 1271  
     public boolean isForceJndiDestinations()
 1272  
     {
 1273  0
         return forceJndiDestinations;
 1274  
     }
 1275  
 
 1276  
     public void setForceJndiDestinations(boolean forceJndiDestinations)
 1277  
     {
 1278  0
         this.forceJndiDestinations = forceJndiDestinations;
 1279  0
     }
 1280  
 
 1281  
     public boolean isDisableTemporaryReplyToDestinations()
 1282  
     {
 1283  0
         return disableTemporaryReplyToDestinations;
 1284  
     }
 1285  
 
 1286  
     public void setDisableTemporaryReplyToDestinations(boolean disableTemporaryReplyToDestinations)
 1287  
     {
 1288  0
         this.disableTemporaryReplyToDestinations = disableTemporaryReplyToDestinations;
 1289  0
     }
 1290  
 
 1291  
     public boolean isReturnOriginalMessageAsReply()
 1292  
     {
 1293  0
         return returnOriginalMessageAsReply;
 1294  
     }
 1295  
 
 1296  
     public void setReturnOriginalMessageAsReply(boolean returnOriginalMessageAsReply)
 1297  
     {
 1298  0
         this.returnOriginalMessageAsReply = returnOriginalMessageAsReply;
 1299  0
     }
 1300  
 
 1301  
     /**
 1302  
      * @return Returns underlying connection factory properties.
 1303  
      */
 1304  
     public Map getConnectionFactoryProperties()
 1305  
     {
 1306  0
         return connectionFactoryProperties;
 1307  
     }
 1308  
 
 1309  
     /**
 1310  
      * @param connectionFactoryProperties properties to be set on the underlying
 1311  
      *                                    ConnectionFactory.
 1312  
      */
 1313  
     public void setConnectionFactoryProperties(Map connectionFactoryProperties)
 1314  
     {
 1315  0
         this.connectionFactoryProperties = connectionFactoryProperties;
 1316  0
     }
 1317  
 
 1318  
     /**
 1319  
      * A synonym for {@link #numberOfConcurrentTransactedReceivers}. Note that
 1320  
      * it affects both transactional and non-transactional scenarios.
 1321  
      *
 1322  
      * @param count number of consumers
 1323  
      */
 1324  
     public void setNumberOfConsumers(int count)
 1325  
     {
 1326  0
         this.numberOfConcurrentTransactedReceivers = count;
 1327  0
     }
 1328  
 
 1329  
     /**
 1330  
      * A synonym for {@link #numberOfConcurrentTransactedReceivers}.
 1331  
      *
 1332  
      * @return number of consumers
 1333  
      */
 1334  
     public int getNumberOfConsumers()
 1335  
     {
 1336  0
         return this.numberOfConcurrentTransactedReceivers;
 1337  
     }
 1338  
 
 1339  
     public boolean isEmbeddedMode()
 1340  
     {
 1341  0
         return embeddedMode;
 1342  
     }
 1343  
 
 1344  
     public void setEmbeddedMode(boolean embeddedMode)
 1345  
     {
 1346  0
         this.embeddedMode = embeddedMode;
 1347  0
     }
 1348  
 
 1349  
     public Boolean getSameRMOverrideValue()
 1350  
     {
 1351  0
         return sameRMOverrideValue;
 1352  
     }
 1353  
 
 1354  
     public void setSameRMOverrideValue(Boolean sameRMOverrideValue)
 1355  
     {
 1356  0
         this.sameRMOverrideValue = sameRMOverrideValue;
 1357  0
     }
 1358  
 }