View Javadoc

1   /*
2    * $Id: JmsConnector.java 7976 2007-08-21 14:26:13Z 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, MuleManager.getInstance()
255                     .getTransactionManager());
256             }
257         }
258 
259         if (username != null)
260         {
261             connection = jmsSupport.createConnection(connectionFactory, username, password);
262         }
263         else
264         {
265             connection = jmsSupport.createConnection(connectionFactory);
266         }
267 
268         if (clientId != null)
269         {
270             connection.setClientID(getClientId());
271         }
272 
273         // Register a JMS exception listener to detect failed connections.
274         // Existing connection strategy will be used to recover.
275 
276         if (recoverJmsConnections && connectionStrategy != null && connection != null)
277         {
278             connection.setExceptionListener(new ExceptionListener()
279             {
280                 public void onException(JMSException jmsException)
281                 {
282                     logger.debug("About to recycle myself due to remote JMS connection shutdown.");
283                     final JmsConnector jmsConnector = JmsConnector.this;
284                     try
285                     {
286                         jmsConnector.stopConnector();
287                         jmsConnector.initialised.set(false);
288                     }
289                     catch (UMOException e)
290                     {
291                         logger.warn(e.getMessage(), e);
292                     }
293 
294                     try
295                     {
296                         connectionStrategy.connect(jmsConnector);
297                         jmsConnector.initialise();
298                         jmsConnector.startConnector();
299                     }
300                     catch (FatalConnectException fcex)
301                     {
302                         logger.fatal("Failed to reconnect to JMS server. I'm giving up.");
303                     }
304                     catch (UMOException umoex)
305                     {
306                         throw new UnhandledException("Failed to recover a connector.", umoex);
307                     }
308                 }
309             });
310         }
311 
312         return connection;
313     }
314 
315     protected void doConnect() throws ConnectException
316     {
317         try
318         {
319             // have to instanciate it here, and not earlier in
320             // MuleXmlConfigurationBuilder, as
321             // native factory may initiate immediate connections, and that is not
322             // what we
323             // want if the descriptor's initial state is paused.
324             if (connectionFactoryClass != null)
325             {
326                 connectionFactory = (ConnectionFactory)ClassUtils.instanciateClass(connectionFactoryClass,
327                     ClassUtils.NO_ARGS);
328             }
329 
330             // If we have a connection factory, there is no need to initialise
331             // the JndiContext
332             if (connectionFactory == null || jndiInitialFactory != null)
333             {
334                 initJndiContext();
335             }
336             else
337             {
338                 // Set these to false so that the jndiContext
339                 // will not be used by the JmsSupport classes
340                 jndiDestinations = false;
341                 forceJndiDestinations = false;
342             }
343 
344             if (jmsSupport == null)
345             {
346                 if (JmsConstants.JMS_SPECIFICATION_102B.equals(specification))
347                 {
348                     jmsSupport = new Jms102bSupport(this, jndiContext, jndiDestinations,
349                         forceJndiDestinations);
350                 }
351                 else
352                 {
353                     jmsSupport = new Jms11Support(this, jndiContext, jndiDestinations, forceJndiDestinations);
354                 }
355             }
356             if (connectionFactory == null)
357             {
358                 connectionFactory = createConnectionFactory();
359             }
360             if (connectionFactoryProperties != null && !connectionFactoryProperties.isEmpty())
361             {
362                 // apply connection factory properties
363                 BeanUtils.populateWithoutFail(connectionFactory, connectionFactoryProperties, true);
364             }
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 doDisconnect() throws ConnectException
386     {
387         try
388         {
389             if (connection != null)
390             {
391                 connection.close();
392             }
393         }
394         catch (Exception e)
395         {
396             throw new ConnectException(e, this);
397         }
398         finally
399         {
400             // connectionFactory = null;
401             connection = null;
402         }
403     }
404 
405     public UMOMessageAdapter getMessageAdapter(Object message) throws MessagingException
406     {
407         JmsMessageAdapter adapter = (JmsMessageAdapter)super.getMessageAdapter(message);
408         adapter.setSpecification(this.getSpecification());
409         return adapter;
410     }
411 
412     protected Object getReceiverKey(UMOComponent component, UMOEndpoint endpoint)
413     {
414         return component.getDescriptor().getName() + "~" + endpoint.getEndpointURI().getAddress();
415     }
416 
417     public Session getSessionFromTransaction()
418     {
419         UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
420         if (tx != null)
421         {
422             if (tx.hasResource(connection))
423             {
424                 if (logger.isDebugEnabled())
425                 {
426                     logger.debug("Retrieving jms session from current transaction " + tx);
427                 }
428 
429                 return (Session)tx.getResource(connection);
430             }
431         }
432         return null;
433     }
434 
435     public Session getSession(UMOImmutableEndpoint endpoint) throws JMSException
436     {
437         final boolean topic = getTopicResolver().isTopic(endpoint);
438         return getSession(endpoint.getTransactionConfig().isTransacted(), topic);
439     }
440 
441     public Session getSession(boolean transacted, boolean topic) throws JMSException
442     {
443         if (!isConnected())
444         {
445             throw new JMSException("Not connected");
446         }
447         Session session = getSessionFromTransaction();
448         if (session != null)
449         {
450             return session;
451         }
452 
453         UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
454 
455         if (logger.isDebugEnabled())
456         {
457             logger.debug(MessageFormat.format(
458                     "Retrieving new jms session from connection: " +
459                     "topic={0}, transacted={1}, ack mode={2}, nolocal={3}",
460                     new Object[]{Boolean.valueOf(topic),
461                                  Boolean.valueOf(transacted),
462                                  new Integer(acknowledgementMode),
463                                  Boolean.valueOf(noLocal)}));
464         }
465 
466         session = jmsSupport.createSession(connection, topic, transacted, acknowledgementMode, noLocal);
467         if (tx != null)
468         {
469             logger.debug("Binding session to current transaction");
470             try
471             {
472                 tx.bindResource(connection, session);
473             }
474             catch (TransactionException e)
475             {
476                 throw new RuntimeException("Could not bind session to current transaction", e);
477             }
478         }
479         return session;
480     }
481 
482     protected void doStart() throws UMOException
483     {
484         if (connection != null)
485         {
486             try
487             {
488                 connection.start();
489             }
490             catch (JMSException e)
491             {
492                 throw new LifecycleException(CoreMessages.failedToStart("Jms Connection"), e);
493             }
494         }
495     }
496 
497     protected void doStop() throws UMOException
498     {
499         // template method
500     }
501 
502     public String getProtocol()
503     {
504         return "jms";
505     }
506 
507     /**
508      * @return Returns the acknowledgeMode.
509      */
510     public int getAcknowledgementMode()
511     {
512         return acknowledgementMode;
513     }
514 
515     /**
516      * @param acknowledgementMode The acknowledgementMode to set.
517      */
518     public void setAcknowledgementMode(int acknowledgementMode)
519     {
520         this.acknowledgementMode = acknowledgementMode;
521     }
522 
523     /**
524      * @return Returns the connectionFactoryJndiName.
525      */
526     public String getConnectionFactoryJndiName()
527     {
528         return connectionFactoryJndiName;
529     }
530 
531     /**
532      * @param connectionFactoryJndiName The connectionFactoryJndiName to set.
533      */
534     public void setConnectionFactoryJndiName(String connectionFactoryJndiName)
535     {
536         this.connectionFactoryJndiName = connectionFactoryJndiName;
537     }
538 
539     /**
540      * @return Returns the durable.
541      */
542     public boolean isDurable()
543     {
544         return durable;
545     }
546 
547     /**
548      * @param durable The durable to set.
549      */
550     public void setDurable(boolean durable)
551     {
552         this.durable = durable;
553     }
554 
555     /**
556      * @return Returns the noLocal.
557      */
558     public boolean isNoLocal()
559     {
560         return noLocal;
561     }
562 
563     /**
564      * @param noLocal The noLocal to set.
565      */
566     public void setNoLocal(boolean noLocal)
567     {
568         this.noLocal = noLocal;
569     }
570 
571     /**
572      * @return Returns the persistentDelivery.
573      */
574     public boolean isPersistentDelivery()
575     {
576         return persistentDelivery;
577     }
578 
579     /**
580      * @param persistentDelivery The persistentDelivery to set.
581      */
582     public void setPersistentDelivery(boolean persistentDelivery)
583     {
584         this.persistentDelivery = persistentDelivery;
585     }
586 
587     /**
588      * Sets <code>honorQosHeaders</code> property, which determines whether <code>JmsMessageDispatcher</code>
589      * should honor incoming message's QoS headers (JMSPriority, JMSDeliveryMode).
590      * @param honorQosHeaders <code>true</code> if <code>JmsMessageDispatcher</code> should honor incoming
591      * message's QoS headers; otherwise <code>false</code> Default is <code>false</code>, meaning that
592      * connector settings will override message headers.
593      */
594     public void setHonorQosHeaders(boolean honorQosHeaders)
595     {
596         this.honorQosHeaders = honorQosHeaders;
597     }
598 
599     /**
600      * Gets the value of <code>honorQosHeaders</code> property.
601      * @return <code>true</code> if <code>JmsMessageDispatcher</code> should honor incoming
602      * message's QoS headers; otherwise <code>false</code> Default is <code>false</code>, meaning that
603      * connector settings will override message headers.
604      */
605     public boolean isHonorQosHeaders()
606     {
607         return honorQosHeaders;
608     }
609     
610     /**
611      * @return Returns the JNDI providerProperties.
612      * @since 1.1
613      */
614     public Map getJndiProviderProperties()
615     {
616         return jndiProviderProperties;
617     }
618 
619     /**
620      * @param jndiProviderProperties The JNDI providerProperties to set.
621      * @since 1.1
622      */
623     public void setJndiProviderProperties(final Map jndiProviderProperties)
624     {
625         this.jndiProviderProperties = jndiProviderProperties;
626     }
627 
628     /**
629      * @return Returns underlying connection factory properties.
630      */
631     public Map getConnectionFactoryProperties()
632     {
633         return connectionFactoryProperties;
634     }
635 
636     /**
637      * @param connectionFactoryProperties properties to be set on the underlying
638      *            ConnectionFactory.
639      */
640     public void setConnectionFactoryProperties(final Map connectionFactoryProperties)
641     {
642         this.connectionFactoryProperties = connectionFactoryProperties;
643     }
644 
645     public String getJndiInitialFactory()
646     {
647         return jndiInitialFactory;
648     }
649 
650     public void setJndiInitialFactory(String jndiInitialFactory)
651     {
652         this.jndiInitialFactory = jndiInitialFactory;
653     }
654 
655     public String getJndiProviderUrl()
656     {
657         return jndiProviderUrl;
658     }
659 
660     public void setJndiProviderUrl(String jndiProviderUrl)
661     {
662         this.jndiProviderUrl = jndiProviderUrl;
663     }
664 
665     public ConnectionFactory getConnectionFactory()
666     {
667         return connectionFactory;
668     }
669 
670     public void setConnectionFactory(ConnectionFactory connectionFactory)
671     {
672         this.connectionFactory = connectionFactory;
673     }
674 
675     public String getConnectionFactoryClass()
676     {
677         return connectionFactoryClass;
678     }
679 
680     public void setConnectionFactoryClass(String connectionFactoryClass)
681     {
682         this.connectionFactoryClass = connectionFactoryClass;
683     }
684 
685     public JmsSupport getJmsSupport()
686     {
687         return jmsSupport;
688     }
689 
690     public void setJmsSupport(JmsSupport jmsSupport)
691     {
692         this.jmsSupport = jmsSupport;
693     }
694 
695     public String getSpecification()
696     {
697         return specification;
698     }
699 
700     public void setSpecification(String specification)
701     {
702         this.specification = specification;
703     }
704 
705     public boolean isJndiDestinations()
706     {
707         return jndiDestinations;
708     }
709 
710     public void setJndiDestinations(boolean jndiDestinations)
711     {
712         this.jndiDestinations = jndiDestinations;
713     }
714 
715     public boolean isForceJndiDestinations()
716     {
717         return forceJndiDestinations;
718     }
719 
720     public void setForceJndiDestinations(boolean forceJndiDestinations)
721     {
722         this.forceJndiDestinations = forceJndiDestinations;
723     }
724 
725     public Context getJndiContext()
726     {
727         return jndiContext;
728     }
729 
730     public void setJndiContext(Context jndiContext)
731     {
732         this.jndiContext = jndiContext;
733     }
734 
735     public void setRecoverJmsConnections(boolean recover)
736     {
737         this.recoverJmsConnections = recover;
738     }
739 
740     public boolean isRecoverJmsConnections()
741     {
742         return this.recoverJmsConnections;
743     }
744 
745     protected RedeliveryHandler createRedeliveryHandler()
746         throws IllegalAccessException, NoSuchMethodException, InvocationTargetException,
747         InstantiationException, ClassNotFoundException
748     {
749         if (redeliveryHandler != null)
750         {
751             return (RedeliveryHandler)ClassUtils.instanciateClass(redeliveryHandler, ClassUtils.NO_ARGS);
752         }
753         else
754         {
755             return new DefaultRedeliveryHandler();
756         }
757     }
758 
759     public ReplyToHandler getReplyToHandler()
760     {
761         return new JmsReplyToHandler(this, defaultResponseTransformer);
762     }
763 
764     public String getUsername()
765     {
766         return username;
767     }
768 
769     public void setUsername(String username)
770     {
771         this.username = username;
772     }
773 
774     public String getPassword()
775     {
776         return password;
777     }
778 
779     public void setPassword(String password)
780     {
781         this.password = password;
782     }
783 
784     /**
785      * @return Returns the connection.
786      */
787     public Connection getConnection()
788     {
789         return connection;
790     }
791 
792     public String getClientId()
793     {
794         return clientId;
795     }
796 
797     public void setClientId(String clientId)
798     {
799         this.clientId = clientId;
800     }
801 
802     public int getMaxRedelivery()
803     {
804         return maxRedelivery;
805     }
806 
807     public void setMaxRedelivery(int maxRedelivery)
808     {
809         this.maxRedelivery = maxRedelivery;
810     }
811 
812     public String getRedeliveryHandler()
813     {
814         return redeliveryHandler;
815     }
816 
817     public void setRedeliveryHandler(String redeliveryHandler)
818     {
819         this.redeliveryHandler = redeliveryHandler;
820     }
821 
822     public boolean isRemoteSyncEnabled()
823     {
824         return true;
825     }
826 
827 
828     /**
829      * Getter for property 'topicResolver'.
830      *
831      * @return Value for property 'topicResolver'.
832      */
833     public JmsTopicResolver getTopicResolver ()
834     {
835         return topicResolver;
836     }
837 
838     /**
839      * Setter for property 'topicResolver'.
840      *
841      * @param topicResolver Value to set for property 'topicResolver'.
842      */
843     public void setTopicResolver (final JmsTopicResolver topicResolver)
844     {
845         this.topicResolver = topicResolver;
846     }
847 
848     /**
849      * Getter for property 'eagerConsumer'. Default
850      * is {@code true}.
851      *
852      * @return Value for property 'eagerConsumer'.
853      * @see #eagerConsumer
854      */
855     public boolean isEagerConsumer ()
856     {
857         return eagerConsumer;
858     }
859 
860     /**
861      * A value of {@code true} will create a consumer on
862      * connect, in contrast to lazy instantiation in the poll loop.
863      * This setting very much depends on the JMS vendor.
864      * Affects transactional receivers, typical symptoms are:
865      * <ul>
866      * <li> consumer thread hanging forever, though a message is
867      * available
868      * <li>failure to consume the first message (the rest
869      * are fine)
870      * </ul>
871      * <p/>
872      *
873      * @param eagerConsumer Value to set for property 'eagerConsumer'.
874      * @see #eagerConsumer
875      * @see org.mule.providers.jms.XaTransactedJmsMessageReceiver
876      */
877     public void setEagerConsumer (final boolean eagerConsumer)
878     {
879         this.eagerConsumer = eagerConsumer;
880     }
881 
882     public void onNotification(UMOServerNotification notification)
883     {
884         if (notification.getAction() == ConnectionNotification.CONNECTION_DISCONNECTED
885             || notification.getAction() == ConnectionNotification.CONNECTION_FAILED)
886         {
887             // Remove all dispatchers as any cached session will be invalidated
888             disposeDispatchers();
889             // TODO should we dispose receivers here as well (in case they are
890             // transactional)
891             // gives a harmless NPE at
892             // AbstractConnector.connect(AbstractConnector.java:927)
893             // disposeReceivers();
894         }
895     }
896 
897     public boolean isCacheJmsSessions()
898     {
899         return cacheJmsSessions;
900     }
901 
902     public void setCacheJmsSessions(boolean cacheJmsSessions)
903     {
904         this.cacheJmsSessions = cacheJmsSessions;
905     }
906 
907     /**
908      * This method may be overridden in case a certain JMS implementation does not
909      * support all the standard JMS properties.
910      */
911     public boolean supportsProperty(String property)
912     {
913         return true;
914     }
915 
916     /**
917      * This method may be overridden in order to apply pre-processing to the message
918      * as soon as it arrives.
919      * 
920      * @param message - the incoming message
921      * @param session - the JMS session
922      * @return the preprocessed message
923      */
924     public javax.jms.Message preProcessMessage(javax.jms.Message message, Session session) throws Exception
925     {
926         return message;
927     }
928 
929     /**
930      * Closes the MessageProducer
931      * 
932      * @param producer
933      * @throws JMSException
934      */
935     public void close(MessageProducer producer) throws JMSException
936     {
937         if (producer != null)
938         {
939             producer.close();
940         }
941     }
942 
943     /**
944      * Closes the MessageProducer without throwing an exception (an error message is
945      * logged instead).
946      * 
947      * @param producer
948      */
949     public void closeQuietly(MessageProducer producer)
950     {
951         try
952         {
953             close(producer);
954         }
955         catch (JMSException e)
956         {
957             logger.error("Failed to close jms message producer", e);
958         }
959     }
960 
961     /**
962      * Closes the MessageConsumer
963      * 
964      * @param consumer
965      * @throws JMSException
966      */
967     public void close(MessageConsumer consumer) throws JMSException
968     {
969         if (consumer != null)
970         {
971             consumer.close();
972         }
973     }
974 
975     /**
976      * Closes the MessageConsumer without throwing an exception (an error message is
977      * logged instead).
978      * 
979      * @param consumer
980      */
981     public void closeQuietly(MessageConsumer consumer)
982     {
983         try
984         {
985             close(consumer);
986         }
987         catch (JMSException e)
988         {
989             logger.error("Failed to close jms message consumer", e);
990         }
991     }
992 
993     /**
994      * Closes the Session
995      * 
996      * @param session
997      * @throws JMSException
998      */
999     public void close(Session session) throws JMSException
1000     {
1001         if (session != null)
1002         {
1003             session.close();
1004         }
1005     }
1006 
1007     /**
1008      * Closes the Session without throwing an exception (an error message is logged
1009      * instead).
1010      * 
1011      * @param session
1012      */
1013     public void closeQuietly(Session session)
1014     {
1015         try
1016         {
1017             close(session);
1018         }
1019         catch (JMSException e)
1020         {
1021             logger.error("Failed to close jms session consumer", e);
1022         }
1023     }
1024 
1025     /**
1026      * Closes the TemporaryQueue
1027      * 
1028      * @param tempQueue
1029      * @throws JMSException
1030      */
1031     public void close(TemporaryQueue tempQueue) throws JMSException
1032     {
1033         if (tempQueue != null)
1034         {
1035             tempQueue.delete();
1036         }
1037     }
1038 
1039     /**
1040      * Closes the TemporaryQueue without throwing an exception (an error message is
1041      * logged instead).
1042      * 
1043      * @param tempQueue
1044      */
1045     public void closeQuietly(TemporaryQueue tempQueue)
1046     {
1047         try
1048         {
1049             close(tempQueue);
1050         }
1051         catch (JMSException e)
1052         {
1053             if (logger.isErrorEnabled())
1054             {
1055                 String queueName = "";
1056                 try
1057                 {
1058                     queueName = tempQueue.getQueueName();
1059                 }
1060                 catch (JMSException innerEx)
1061                 {
1062                     // ignore, we are just trying to get the queue name
1063                 }
1064                 logger.info(MessageFormat.format(
1065                         "Faled to delete a temporary queue '{0}' Reason: {1}",
1066                         new Object[] {queueName, e.getMessage()}));
1067             }
1068         }
1069     }
1070 
1071     /**
1072      * Closes the TemporaryTopic
1073      * 
1074      * @param tempTopic
1075      * @throws JMSException
1076      */
1077     public void close(TemporaryTopic tempTopic) throws JMSException
1078     {
1079         if (tempTopic != null)
1080         {
1081             tempTopic.delete();
1082         }
1083     }
1084 
1085     /**
1086      * Closes the TemporaryTopic without throwing an exception (an error message is
1087      * logged instead).
1088      * 
1089      * @param tempTopic
1090      */
1091     public void closeQuietly(TemporaryTopic tempTopic)
1092     {
1093         try
1094         {
1095             close(tempTopic);
1096         }
1097         catch (JMSException e)
1098         {
1099             if (logger.isErrorEnabled())
1100             {
1101                 String topicName = "";
1102                 try
1103                 {
1104                     topicName = tempTopic.getTopicName();
1105                 }
1106                 catch (JMSException innerEx)
1107                 {
1108                     // ignore, we are just trying to get the topic name
1109                 }
1110                 logger.error("Faled to delete a temporary topic " + topicName, e);
1111             }
1112         }
1113     }
1114 }