View Javadoc

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