View Javadoc

1   /*
2    * $Id: JmsConnector.java 11728 2008-05-13 07:31:11Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.providers.jms;
12  
13  import org.mule.MuleManager;
14  import org.mule.config.ExceptionHelper;
15  import org.mule.config.i18n.CoreMessages;
16  import org.mule.impl.internal.notifications.ConnectionNotification;
17  import org.mule.impl.internal.notifications.ConnectionNotificationListener;
18  import org.mule.impl.internal.notifications.NotificationException;
19  import org.mule.providers.AbstractConnector;
20  import org.mule.providers.ConnectException;
21  import org.mule.providers.FatalConnectException;
22  import org.mule.providers.ReplyToHandler;
23  import org.mule.providers.jms.i18n.JmsMessages;
24  import org.mule.providers.jms.xa.ConnectionFactoryWrapper;
25  import org.mule.providers.service.TransportFactoryException;
26  import org.mule.transaction.TransactionCoordination;
27  import org.mule.umo.MessagingException;
28  import org.mule.umo.TransactionException;
29  import org.mule.umo.UMOComponent;
30  import org.mule.umo.UMOException;
31  import org.mule.umo.UMOTransaction;
32  import org.mule.umo.endpoint.UMOEndpoint;
33  import org.mule.umo.endpoint.UMOImmutableEndpoint;
34  import org.mule.umo.lifecycle.InitialisationException;
35  import org.mule.umo.lifecycle.LifecycleException;
36  import org.mule.umo.manager.UMOServerNotification;
37  import org.mule.umo.provider.UMOMessageAdapter;
38  import org.mule.util.BeanUtils;
39  import org.mule.util.ClassUtils;
40  
41  import java.lang.reflect.InvocationTargetException;
42  import java.text.MessageFormat;
43  import java.util.Hashtable;
44  import java.util.Map;
45  
46  import javax.jms.Connection;
47  import javax.jms.ConnectionFactory;
48  import javax.jms.ExceptionListener;
49  import javax.jms.JMSException;
50  import javax.jms.MessageConsumer;
51  import javax.jms.MessageProducer;
52  import javax.jms.Session;
53  import javax.jms.TemporaryQueue;
54  import javax.jms.TemporaryTopic;
55  import javax.jms.XAConnectionFactory;
56  import javax.naming.Context;
57  import javax.naming.InitialContext;
58  import javax.naming.NamingException;
59  
60  import org.apache.commons.lang.UnhandledException;
61  
62  /**
63   * <code>JmsConnector</code> is a JMS 1.0.2b compliant connector that can be used
64   * by a Mule endpoint. The connector supports all JMS functionality including topics
65   * and queues, durable subscribers, acknowledgement modes and local transactions.
66   */
67  
68  public class JmsConnector extends AbstractConnector implements ConnectionNotificationListener
69  {
70      /* Register the Jms Exception reader if this class gets loaded */
71      static
72      {
73          ExceptionHelper.registerExceptionReader(new JmsExceptionReader());
74      }
75  
76      private String connectionFactoryJndiName;
77  
78      private ConnectionFactory connectionFactory;
79  
80      private String connectionFactoryClass;
81  
82      private String jndiInitialFactory;
83  
84      private String jndiProviderUrl;
85  
86      private int acknowledgementMode = Session.AUTO_ACKNOWLEDGE;
87  
88      private String clientId;
89  
90      private boolean durable;
91  
92      private boolean noLocal;
93  
94      private boolean persistentDelivery;
95      
96      private boolean honorQosHeaders;
97  
98      private Map jndiProviderProperties;
99  
100     private Map connectionFactoryProperties;
101 
102     private Connection connection;
103 
104     private String specification = JmsConstants.JMS_SPECIFICATION_102B;
105 
106     private JmsSupport jmsSupport;
107 
108     private Context jndiContext;
109 
110     private boolean jndiDestinations = false;
111 
112     private boolean forceJndiDestinations = false;
113 
114     public String username = null;
115 
116     public String password = null;
117 
118     private int maxRedelivery = 0;
119 
120     private String redeliveryHandler = DefaultRedeliveryHandler.class.getName();
121 
122     private boolean cacheJmsSessions = false;
123 
124     private boolean recoverJmsConnections = true;
125 
126     private JmsTopicResolver topicResolver;
127 
128     /**
129      * Whether to create a consumer on connect.
130      */
131     private boolean eagerConsumer = true;
132 
133     public JmsConnector()
134     {
135         super();
136         topicResolver = new DefaultJmsTopicResolver(this);
137     }
138 
139     protected void doInitialise() throws InitialisationException
140     {
141 
142         try
143         {
144             MuleManager.getInstance().registerListener(this, getName());
145             //since transformers are stateful and have the endpoint set on them,we should have different transformers for each connector
146             defaultInboundTransformer = serviceDescriptor.createNewInboundTransformer();
147             defaultOutboundTransformer = serviceDescriptor.createNewOutboundTransformer();
148             defaultResponseTransformer = serviceDescriptor.createNewResponseTransformer();
149         }
150         catch (NotificationException nex)
151         {
152             throw new InitialisationException(nex, this);
153         }
154         catch (TransportFactoryException tex)
155         {
156             throw new InitialisationException(tex, this);
157         }
158     }
159 
160     protected void doDispose()
161     {
162         if (connection != null)
163         {
164             try
165             {
166                 connection.close();
167             }
168             catch (JMSException e)
169             {
170                 logger.error("Jms connector failed to dispose properly: ", e);
171             }
172             connection = null;
173         }
174 
175         if (jndiContext != null)
176         {
177             try
178             {
179                 jndiContext.close();
180             }
181             catch (NamingException e)
182             {
183                 logger.error("Jms connector failed to dispose properly: ", e);
184             }
185             // need this line to flag for reinitialization in ConnectionStrategy
186             jndiContext = null;
187         }
188     }
189 
190     protected void initJndiContext() throws NamingException, InitialisationException
191     {
192         if (jndiContext == null)
193         {
194             Hashtable props = new Hashtable();
195 
196             if (jndiInitialFactory != null)
197             {
198                 props.put(Context.INITIAL_CONTEXT_FACTORY, jndiInitialFactory);
199             }
200             else if (jndiProviderProperties == null
201                      || !jndiProviderProperties.containsKey(Context.INITIAL_CONTEXT_FACTORY))
202             {
203                 throw new InitialisationException(CoreMessages.objectIsNull("jndiInitialFactory"), this);
204             }
205 
206             if (jndiProviderUrl != null)
207             {
208                 props.put(Context.PROVIDER_URL, jndiProviderUrl);
209             }
210 
211             if (jndiProviderProperties != null)
212             {
213                 props.putAll(jndiProviderProperties);
214             }
215             jndiContext = new InitialContext(props);
216         }
217     }
218 
219     protected void setConnection(Connection connection)
220     {
221         this.connection = connection;
222     }
223 
224     protected ConnectionFactory createConnectionFactory() throws InitialisationException, NamingException
225     {
226 
227         Object temp = jndiContext.lookup(connectionFactoryJndiName);
228 
229         if (temp instanceof ConnectionFactory)
230         {
231             return (ConnectionFactory)temp;
232         }
233         else
234         {
235             throw new InitialisationException(
236                 JmsMessages.invalidResourceType(ConnectionFactory.class, 
237                     (temp == null ? null : temp.getClass())), this);
238         }
239     }
240 
241     protected Connection createConnection() throws NamingException, JMSException, InitialisationException
242     {
243         Connection connection;
244 
245         if (connectionFactory == null)
246         {
247             connectionFactory = createConnectionFactory();
248         }
249 
250         if (connectionFactory != null && connectionFactory instanceof XAConnectionFactory)
251         {
252             if (MuleManager.getInstance().getTransactionManager() != null)
253             {
254                 connectionFactory = new ConnectionFactoryWrapper(connectionFactory);
255             }
256         }
257 
258         if (username != null)
259         {
260             connection = jmsSupport.createConnection(connectionFactory, username, password);
261         }
262         else
263         {
264             connection = jmsSupport.createConnection(connectionFactory);
265         }
266 
267         if (clientId != null)
268         {
269             connection.setClientID(getClientId());
270         }
271 
272         // Register a JMS exception listener to detect failed connections.
273         // Existing connection strategy will be used to recover.
274 
275         if (recoverJmsConnections && connectionStrategy != null && connection != null)
276         {
277             connection.setExceptionListener(new ExceptionListener()
278             {
279                 public void onException(JMSException jmsException)
280                 {
281                     logger.debug("About to recycle myself due to remote JMS connection shutdown.");
282                     final JmsConnector jmsConnector = JmsConnector.this;
283                     try
284                     {
285                         jmsConnector.stopConnector();
286                         jmsConnector.initialised.set(false);
287                     }
288                     catch (UMOException e)
289                     {
290                         logger.warn(e.getMessage(), e);
291                     }
292 
293                     try
294                     {
295                         connectionStrategy.connect(jmsConnector);
296                         jmsConnector.initialise();
297                         jmsConnector.startConnector();
298                     }
299                     catch (FatalConnectException fcex)
300                     {
301                         logger.fatal("Failed to reconnect to JMS server. I'm giving up.");
302                     }
303                     catch (UMOException umoex)
304                     {
305                         throw new UnhandledException("Failed to recover a connector.", umoex);
306                     }
307                 }
308             });
309         }
310 
311         return connection;
312     }
313 
314     protected void doConnect() throws ConnectException
315     {
316         try
317         {
318             // have to instanciate it here, and not earlier in
319             // MuleXmlConfigurationBuilder, as
320             // native factory may initiate immediate connections, and that is not
321             // what we
322             // want if the descriptor's initial state is paused.
323             if (connectionFactoryClass != null)
324             {
325                 connectionFactory = (ConnectionFactory)ClassUtils.instanciateClass(connectionFactoryClass,
326                     ClassUtils.NO_ARGS);
327             }
328 
329             // If we have a connection factory, there is no need to initialise
330             // the JndiContext
331             if (connectionFactory == null || jndiInitialFactory != null)
332             {
333                 initJndiContext();
334             }
335             else
336             {
337                 // Set these to false so that the jndiContext
338                 // will not be used by the JmsSupport classes
339                 jndiDestinations = false;
340                 forceJndiDestinations = false;
341             }
342 
343             if (jmsSupport == null)
344             {
345                 if (JmsConstants.JMS_SPECIFICATION_102B.equals(specification))
346                 {
347                     jmsSupport = new Jms102bSupport(this, jndiContext, jndiDestinations,
348                         forceJndiDestinations);
349                 }
350                 else
351                 {
352                     jmsSupport = new Jms11Support(this, jndiContext, jndiDestinations, forceJndiDestinations);
353                 }
354             }
355             if (connectionFactory == null)
356             {
357                 connectionFactory = createConnectionFactory();
358             }
359             if (connectionFactoryProperties != null && !connectionFactoryProperties.isEmpty())
360             {
361                 // apply connection factory properties
362                 BeanUtils.populateWithoutFail(connectionFactory, connectionFactoryProperties, true);
363             }
364             applyVendorSpecificConnectionFactoryProperties();
365         }
366         catch (Exception e)
367         {
368             throw new ConnectException(CoreMessages.failedToCreate("Jms Connector"), e, this);
369         }
370 
371         try
372         {
373             connection = createConnection();
374             if (started.get())
375             {
376                 connection.start();
377             }
378         }
379         catch (Exception e)
380         {
381             throw new ConnectException(e, this);
382         }
383     }
384 
385     protected void applyVendorSpecificConnectionFactoryProperties(){
386         //template method
387     }
388 
389     protected void doDisconnect() throws ConnectException
390     {
391         try
392         {
393             if (connection != null)
394             {
395                 connection.close();
396             }
397         }
398         catch (Exception e)
399         {
400             throw new ConnectException(e, this);
401         }
402         finally
403         {
404             // connectionFactory = null;
405             connection = null;
406         }
407     }
408 
409     public UMOMessageAdapter getMessageAdapter(Object message) throws MessagingException
410     {
411         JmsMessageAdapter adapter = (JmsMessageAdapter)super.getMessageAdapter(message);
412         adapter.setSpecification(this.getSpecification());
413         return adapter;
414     }
415 
416     protected Object getReceiverKey(UMOComponent component, UMOEndpoint endpoint)
417     {
418         return component.getDescriptor().getName() + "~" + endpoint.getEndpointURI().getAddress();
419     }
420 
421     public Session getSessionFromTransaction()
422     {
423         UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
424         if (tx != null)
425         {
426             if (tx.hasResource(connection))
427             {
428                 if (logger.isDebugEnabled())
429                 {
430                     logger.debug("Retrieving jms session from current transaction " + tx);
431                 }
432 
433                 Session session = (Session) tx.getResource(connection);
434 
435                 if (logger.isDebugEnabled())
436                 {
437                     logger.debug("Using " + session + " bound to transaction " + tx);
438                 }
439 
440                 return session;
441             }
442         }
443         return null;
444     }
445 
446     public Session getSession(UMOImmutableEndpoint endpoint) throws JMSException
447     {
448         final boolean topic = getTopicResolver().isTopic(endpoint);
449         return getSession(endpoint.getTransactionConfig().isTransacted(), topic);
450     }
451 
452     public Session getSession(boolean transacted, boolean topic) throws JMSException
453     {
454         if (!isConnected())
455         {
456             throw new JMSException("Not connected");
457         }
458         Session session = getSessionFromTransaction();
459         if (session != null)
460         {
461             return session;
462         }
463 
464         UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
465 
466         if (logger.isDebugEnabled())
467         {
468             logger.debug(MessageFormat.format(
469                     "Retrieving new jms session from connection: " +
470                     "topic={0}, transacted={1}, ack mode={2}, nolocal={3}",
471                     new Object[]{Boolean.valueOf(topic),
472                                  Boolean.valueOf(transacted),
473                                  new Integer(acknowledgementMode),
474                                  Boolean.valueOf(noLocal)}));
475         }
476 
477         session = jmsSupport.createSession(connection, topic, transacted, acknowledgementMode, noLocal);
478         if (tx != null)
479         {
480             logger.debug("Binding session " + session + " to current transaction " + tx);
481             try
482             {
483                 tx.bindResource(connection, session);
484             }
485             catch (TransactionException e)
486             {
487                 closeQuietly(session);
488                 throw new RuntimeException("Could not bind session to current transaction", e);
489             }
490         }
491         return session;
492     }
493 
494     protected void doStart() throws UMOException
495     {
496         if (connection != null)
497         {
498             try
499             {
500                 connection.start();
501             }
502             catch (JMSException e)
503             {
504                 throw new LifecycleException(CoreMessages.failedToStart("Jms Connection"), e);
505             }
506         }
507     }
508 
509     protected void doStop() throws UMOException
510     {
511         // template method
512     }
513 
514     public String getProtocol()
515     {
516         return "jms";
517     }
518 
519     /**
520      * @return Returns the acknowledgeMode.
521      */
522     public int getAcknowledgementMode()
523     {
524         return acknowledgementMode;
525     }
526 
527     /**
528      * @param acknowledgementMode The acknowledgementMode to set.
529      */
530     public void setAcknowledgementMode(int acknowledgementMode)
531     {
532         this.acknowledgementMode = acknowledgementMode;
533     }
534 
535     /**
536      * @return Returns the connectionFactoryJndiName.
537      */
538     public String getConnectionFactoryJndiName()
539     {
540         return connectionFactoryJndiName;
541     }
542 
543     /**
544      * @param connectionFactoryJndiName The connectionFactoryJndiName to set.
545      */
546     public void setConnectionFactoryJndiName(String connectionFactoryJndiName)
547     {
548         this.connectionFactoryJndiName = connectionFactoryJndiName;
549     }
550 
551     /**
552      * @return Returns the durable.
553      */
554     public boolean isDurable()
555     {
556         return durable;
557     }
558 
559     /**
560      * @param durable The durable to set.
561      */
562     public void setDurable(boolean durable)
563     {
564         this.durable = durable;
565     }
566 
567     /**
568      * @return Returns the noLocal.
569      */
570     public boolean isNoLocal()
571     {
572         return noLocal;
573     }
574 
575     /**
576      * @param noLocal The noLocal to set.
577      */
578     public void setNoLocal(boolean noLocal)
579     {
580         this.noLocal = noLocal;
581     }
582 
583     /**
584      * @return Returns the persistentDelivery.
585      */
586     public boolean isPersistentDelivery()
587     {
588         return persistentDelivery;
589     }
590 
591     /**
592      * @param persistentDelivery The persistentDelivery to set.
593      */
594     public void setPersistentDelivery(boolean persistentDelivery)
595     {
596         this.persistentDelivery = persistentDelivery;
597     }
598 
599     /**
600      * Sets <code>honorQosHeaders</code> property, which determines whether <code>JmsMessageDispatcher</code>
601      * should honor incoming message's QoS headers (JMSPriority, JMSDeliveryMode).
602      * @param honorQosHeaders <code>true</code> if <code>JmsMessageDispatcher</code> should honor incoming
603      * message's QoS headers; otherwise <code>false</code> Default is <code>false</code>, meaning that
604      * connector settings will override message headers.
605      */
606     public void setHonorQosHeaders(boolean honorQosHeaders)
607     {
608         this.honorQosHeaders = honorQosHeaders;
609     }
610 
611     /**
612      * Gets the value of <code>honorQosHeaders</code> property.
613      * @return <code>true</code> if <code>JmsMessageDispatcher</code> should honor incoming
614      * message's QoS headers; otherwise <code>false</code> Default is <code>false</code>, meaning that
615      * connector settings will override message headers.
616      */
617     public boolean isHonorQosHeaders()
618     {
619         return honorQosHeaders;
620     }
621     
622     /**
623      * @return Returns the JNDI providerProperties.
624      * @since 1.1
625      */
626     public Map getJndiProviderProperties()
627     {
628         return jndiProviderProperties;
629     }
630 
631     /**
632      * @param jndiProviderProperties The JNDI providerProperties to set.
633      * @since 1.1
634      */
635     public void setJndiProviderProperties(final Map jndiProviderProperties)
636     {
637         this.jndiProviderProperties = jndiProviderProperties;
638     }
639 
640     /**
641      * @return Returns underlying connection factory properties.
642      */
643     public Map getConnectionFactoryProperties()
644     {
645         return connectionFactoryProperties;
646     }
647 
648     /**
649      * @param connectionFactoryProperties properties to be set on the underlying
650      *            ConnectionFactory.
651      */
652     public void setConnectionFactoryProperties(final Map connectionFactoryProperties)
653     {
654         this.connectionFactoryProperties = connectionFactoryProperties;
655     }
656 
657     public String getJndiInitialFactory()
658     {
659         return jndiInitialFactory;
660     }
661 
662     public void setJndiInitialFactory(String jndiInitialFactory)
663     {
664         this.jndiInitialFactory = jndiInitialFactory;
665     }
666 
667     public String getJndiProviderUrl()
668     {
669         return jndiProviderUrl;
670     }
671 
672     public void setJndiProviderUrl(String jndiProviderUrl)
673     {
674         this.jndiProviderUrl = jndiProviderUrl;
675     }
676 
677     public ConnectionFactory getConnectionFactory()
678     {
679         return connectionFactory;
680     }
681 
682     public void setConnectionFactory(ConnectionFactory connectionFactory)
683     {
684         this.connectionFactory = connectionFactory;
685     }
686 
687     public String getConnectionFactoryClass()
688     {
689         return connectionFactoryClass;
690     }
691 
692     public void setConnectionFactoryClass(String connectionFactoryClass)
693     {
694         this.connectionFactoryClass = connectionFactoryClass;
695     }
696 
697     public JmsSupport getJmsSupport()
698     {
699         return jmsSupport;
700     }
701 
702     public void setJmsSupport(JmsSupport jmsSupport)
703     {
704         this.jmsSupport = jmsSupport;
705     }
706 
707     public String getSpecification()
708     {
709         return specification;
710     }
711 
712     public void setSpecification(String specification)
713     {
714         this.specification = specification;
715     }
716 
717     public boolean isJndiDestinations()
718     {
719         return jndiDestinations;
720     }
721 
722     public void setJndiDestinations(boolean jndiDestinations)
723     {
724         this.jndiDestinations = jndiDestinations;
725     }
726 
727     public boolean isForceJndiDestinations()
728     {
729         return forceJndiDestinations;
730     }
731 
732     public void setForceJndiDestinations(boolean forceJndiDestinations)
733     {
734         this.forceJndiDestinations = forceJndiDestinations;
735     }
736 
737     public Context getJndiContext()
738     {
739         return jndiContext;
740     }
741 
742     public void setJndiContext(Context jndiContext)
743     {
744         this.jndiContext = jndiContext;
745     }
746 
747     public void setRecoverJmsConnections(boolean recover)
748     {
749         this.recoverJmsConnections = recover;
750     }
751 
752     public boolean isRecoverJmsConnections()
753     {
754         return this.recoverJmsConnections;
755     }
756 
757     protected RedeliveryHandler createRedeliveryHandler()
758         throws IllegalAccessException, NoSuchMethodException, InvocationTargetException,
759         InstantiationException, ClassNotFoundException
760     {
761         if (redeliveryHandler != null)
762         {
763             return (RedeliveryHandler)ClassUtils.instanciateClass(redeliveryHandler, ClassUtils.NO_ARGS);
764         }
765         else
766         {
767             return new DefaultRedeliveryHandler();
768         }
769     }
770 
771     public ReplyToHandler getReplyToHandler()
772     {
773         return new JmsReplyToHandler(this, defaultResponseTransformer);
774     }
775 
776     public String getUsername()
777     {
778         return username;
779     }
780 
781     public void setUsername(String username)
782     {
783         this.username = username;
784     }
785 
786     public String getPassword()
787     {
788         return password;
789     }
790 
791     public void setPassword(String password)
792     {
793         this.password = password;
794     }
795 
796     /**
797      * @return Returns the connection.
798      */
799     public Connection getConnection()
800     {
801         return connection;
802     }
803 
804     public String getClientId()
805     {
806         return clientId;
807     }
808 
809     public void setClientId(String clientId)
810     {
811         this.clientId = clientId;
812     }
813 
814     public int getMaxRedelivery()
815     {
816         return maxRedelivery;
817     }
818 
819     public void setMaxRedelivery(int maxRedelivery)
820     {
821         this.maxRedelivery = maxRedelivery;
822     }
823 
824     public String getRedeliveryHandler()
825     {
826         return redeliveryHandler;
827     }
828 
829     public void setRedeliveryHandler(String redeliveryHandler)
830     {
831         this.redeliveryHandler = redeliveryHandler;
832     }
833 
834     public boolean isRemoteSyncEnabled()
835     {
836         return true;
837     }
838 
839 
840     /**
841      * Getter for property 'topicResolver'.
842      *
843      * @return Value for property 'topicResolver'.
844      */
845     public JmsTopicResolver getTopicResolver ()
846     {
847         return topicResolver;
848     }
849 
850     /**
851      * Setter for property 'topicResolver'.
852      *
853      * @param topicResolver Value to set for property 'topicResolver'.
854      */
855     public void setTopicResolver (final JmsTopicResolver topicResolver)
856     {
857         this.topicResolver = topicResolver;
858     }
859 
860     /**
861      * Getter for property 'eagerConsumer'. Default
862      * is {@code true}.
863      *
864      * @return Value for property 'eagerConsumer'.
865      * @see #eagerConsumer
866      */
867     public boolean isEagerConsumer ()
868     {
869         return eagerConsumer;
870     }
871 
872     /**
873      * A value of {@code true} will create a consumer on
874      * connect, in contrast to lazy instantiation in the poll loop.
875      * This setting very much depends on the JMS vendor.
876      * Affects transactional receivers, typical symptoms are:
877      * <ul>
878      * <li> consumer thread hanging forever, though a message is
879      * available
880      * <li>failure to consume the first message (the rest
881      * are fine)
882      * </ul>
883      * <p/>
884      *
885      * @param eagerConsumer Value to set for property 'eagerConsumer'.
886      * @see #eagerConsumer
887      * @see org.mule.providers.jms.XaTransactedJmsMessageReceiver
888      */
889     public void setEagerConsumer (final boolean eagerConsumer)
890     {
891         this.eagerConsumer = eagerConsumer;
892     }
893 
894     public void onNotification(UMOServerNotification notification)
895     {
896         if (notification.getAction() == ConnectionNotification.CONNECTION_DISCONNECTED
897             || notification.getAction() == ConnectionNotification.CONNECTION_FAILED)
898         {
899             // Remove all dispatchers as any cached session will be invalidated
900             disposeDispatchers();
901             // TODO should we dispose receivers here as well (in case they are
902             // transactional)
903             // gives a harmless NPE at
904             // AbstractConnector.connect(AbstractConnector.java:927)
905             // disposeReceivers();
906         }
907     }
908 
909     public boolean isCacheJmsSessions()
910     {
911         return cacheJmsSessions;
912     }
913 
914     public void setCacheJmsSessions(boolean cacheJmsSessions)
915     {
916         this.cacheJmsSessions = cacheJmsSessions;
917     }
918 
919     /**
920      * This method may be overridden in case a certain JMS implementation does not
921      * support all the standard JMS properties.
922      */
923     public boolean supportsProperty(String property)
924     {
925         return true;
926     }
927 
928     /**
929      * This method may be overridden in order to apply pre-processing to the message
930      * as soon as it arrives.
931      * 
932      * @param message - the incoming message
933      * @param session - the JMS session
934      * @return the preprocessed message
935      */
936     public javax.jms.Message preProcessMessage(javax.jms.Message message, Session session) throws Exception
937     {
938         return message;
939     }
940 
941     /**
942      * Closes the MessageProducer
943      * 
944      * @param producer
945      * @throws JMSException
946      */
947     public void close(MessageProducer producer) throws JMSException
948     {
949         if (producer != null)
950         {
951             producer.close();
952         }
953     }
954 
955     /**
956      * Closes the MessageProducer without throwing an exception (an error message is
957      * logged instead).
958      * 
959      * @param producer
960      */
961     public void closeQuietly(MessageProducer producer)
962     {
963         try
964         {
965             close(producer);
966         }
967         catch (JMSException e)
968         {
969             logger.error("Failed to close jms message producer", e);
970         }
971     }
972 
973     /**
974      * Closes the MessageConsumer
975      * 
976      * @param consumer
977      * @throws JMSException
978      */
979     public void close(MessageConsumer consumer) throws JMSException
980     {
981         if (consumer != null)
982         {
983             consumer.close();
984         }
985     }
986 
987     /**
988      * Closes the MessageConsumer without throwing an exception (an error message is
989      * logged instead).
990      * 
991      * @param consumer
992      */
993     public void closeQuietly(MessageConsumer consumer)
994     {
995         try
996         {
997             close(consumer);
998         }
999         catch (JMSException e)
1000         {
1001             logger.error("Failed to close jms message consumer", e);
1002         }
1003     }
1004 
1005     /**
1006      * Closes the Session
1007      * 
1008      * @param session
1009      * @throws JMSException
1010      */
1011     public void close(Session session) throws JMSException
1012     {
1013         if (session != null)
1014         {
1015             session.close();
1016         }
1017     }
1018 
1019     /**
1020      * Closes the Session without throwing an exception (an error message is logged
1021      * instead).
1022      * 
1023      * @param session
1024      */
1025     public void closeQuietly(Session session)
1026     {
1027         try
1028         {
1029             close(session);
1030         }
1031         catch (JMSException e)
1032         {
1033             logger.error("Failed to close jms session", e);
1034         }
1035     }
1036 
1037     /**
1038      * Closes the TemporaryQueue
1039      * 
1040      * @param tempQueue
1041      * @throws JMSException
1042      */
1043     public void close(TemporaryQueue tempQueue) throws JMSException
1044     {
1045         if (tempQueue != null)
1046         {
1047             tempQueue.delete();
1048         }
1049     }
1050 
1051     /**
1052      * Closes the TemporaryQueue without throwing an exception (an error message is
1053      * logged instead).
1054      * 
1055      * @param tempQueue
1056      */
1057     public void closeQuietly(TemporaryQueue tempQueue)
1058     {
1059         try
1060         {
1061             close(tempQueue);
1062         }
1063         catch (JMSException e)
1064         {
1065             if (logger.isErrorEnabled())
1066             {
1067                 String queueName = "";
1068                 try
1069                 {
1070                     queueName = tempQueue.getQueueName();
1071                 }
1072                 catch (JMSException innerEx)
1073                 {
1074                     // ignore, we are just trying to get the queue name
1075                 }
1076                 logger.info(MessageFormat.format(
1077                         "Faled to delete a temporary queue '{0}' Reason: {1}",
1078                         new Object[] {queueName, e.getMessage()}));
1079             }
1080         }
1081     }
1082 
1083     /**
1084      * Closes the TemporaryTopic
1085      * 
1086      * @param tempTopic
1087      * @throws JMSException
1088      */
1089     public void close(TemporaryTopic tempTopic) throws JMSException
1090     {
1091         if (tempTopic != null)
1092         {
1093             tempTopic.delete();
1094         }
1095     }
1096 
1097     /**
1098      * Closes the TemporaryTopic without throwing an exception (an error message is
1099      * logged instead).
1100      * 
1101      * @param tempTopic
1102      */
1103     public void closeQuietly(TemporaryTopic tempTopic)
1104     {
1105         try
1106         {
1107             close(tempTopic);
1108         }
1109         catch (JMSException e)
1110         {
1111             if (logger.isErrorEnabled())
1112             {
1113                 String topicName = "";
1114                 try
1115                 {
1116                     topicName = tempTopic.getTopicName();
1117                 }
1118                 catch (JMSException innerEx)
1119                 {
1120                     // ignore, we are just trying to get the topic name
1121                 }
1122                 logger.error("Faled to delete a temporary topic " + topicName, e);
1123             }
1124         }
1125     }
1126 }