View Javadoc

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