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