Project Spring (latest) [3/30/06 5:21 PM]
 
Coverage - org/springframework/jms/core/JmsTemplate.java
1  /*
2   * Copyright 2002-2005 the original author or authors.
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *      http://www.apache.org/licenses/LICENSE-2.0
9   *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.jms.core;
18  
19  import javax.jms.Connection;
20  import javax.jms.ConnectionFactory;
21  import javax.jms.DeliveryMode;
22  import javax.jms.Destination;
23  import javax.jms.JMSException;
24  import javax.jms.Message;
25  import javax.jms.MessageConsumer;
26  import javax.jms.MessageProducer;
27  import javax.jms.Session;
28  import javax.jms.Topic;
29  
30  import org.springframework.jms.JmsException;
31  import org.springframework.jms.connection.ConnectionHolder;
32  import org.springframework.jms.support.JmsUtils;
33  import org.springframework.jms.support.converter.MessageConverter;
34  import org.springframework.jms.support.converter.SimpleMessageConverter;
35  import org.springframework.jms.support.destination.DynamicDestinationResolver;
36  import org.springframework.jms.support.destination.JmsDestinationAccessor;
37  import org.springframework.transaction.support.TransactionSynchronizationManager;
38  
39  /**
40   * Helper class that simplifies JMS access code. This class requires a
41   * JMS 1.1+ provider, because it builds on the domain-independent API.
42   * <b>Use the {@link JmsTemplate102 JmsTemplate102} subclass for
43   * JMS 1.0.2 providers.</b>
44   *
45   * <p>If you want to use dynamic destination creation, you must specify
46   * the type of JMS destination to create, using the "pubSubDomain" property.
47   * For other operations, this is not necessary, in contrast to when working
48   * with JmsTemplate102. Point-to-Point (Queues) is the default domain.
49   *
50   * <p>Default settings for JMS Sessions are "not transacted" and "auto-acknowledge".
51   * As defined by the J2EE specification, the transaction and acknowledgement
52   * parameters are ignored when a JMS Session is created inside an active
53   * transaction, no matter if a JTA transaction or a Spring-managed transaction.
54   *
55   * <p>This template uses a DynamicDestinationResolver and a SimpleMessageConverter
56   * as default strategies for resolving a destination name or converting a message,
57   * respectively.
58   *
59   * @author Mark Pollack
60   * @author Juergen Hoeller
61   * @since 1.1
62   * @see #setConnectionFactory
63   * @see #setPubSubDomain
64   * @see JmsTemplate102
65   * @see #setDestinationResolver
66   * @see #setMessageConverter
67   * @see org.springframework.jms.support.destination.DynamicDestinationResolver
68   * @see org.springframework.jms.support.converter.SimpleMessageConverter
69   * @see javax.jms.Destination
70   * @see javax.jms.Session
71   * @see javax.jms.MessageProducer
72   * @see javax.jms.MessageConsumer
73   */
74  public class JmsTemplate extends JmsDestinationAccessor implements JmsOperations {
75  
76      /**
77      * Default timeout for receive operations:
78      * -1 indicates a blocking receive without timeout.
79      */
80      public static final long DEFAULT_RECEIVE_TIMEOUT = -1;
81  
82  
83      private Object defaultDestination;
84  
85      private MessageConverter messageConverter;
86  
87  
88 0x      private boolean messageIdEnabled = true;
89  
90 0x      private boolean messageTimestampEnabled = true;
91  
92 0x      private boolean pubSubNoLocal = false;
93  
94 0x      private long receiveTimeout = DEFAULT_RECEIVE_TIMEOUT;
95  
96  
97 0x      private boolean explicitQosEnabled = false;
98  
99 0x      private int deliveryMode = Message.DEFAULT_DELIVERY_MODE;
100  
101 0x      private int priority = Message.DEFAULT_PRIORITY;
102  
103 0x      private long timeToLive = Message.DEFAULT_TIME_TO_LIVE;
104  
105  
106      /**
107      * Create a new JmsTemplate for bean-style usage.
108      * <p>Note: The ConnectionFactory has to be set before using the instance.
109      * This constructor can be used to prepare a JmsTemplate via a BeanFactory,
110      * typically setting the ConnectionFactory via setConnectionFactory.
111      * @see #setConnectionFactory
112      */
113 0x      public JmsTemplate() {
114 0x          initDefaultStrategies();
115 0x      }
116  
117      /**
118      * Create a new JmsTemplate, given a ConnectionFactory.
119      * @param connectionFactory the ConnectionFactory to obtain connections from
120      */
121      public JmsTemplate(ConnectionFactory connectionFactory) {
122 0x          this();
123 0x          setConnectionFactory(connectionFactory);
124 0x          afterPropertiesSet();
125 0x      }
126  
127      /**
128      * Initialize the default implementations for the template's strategies:
129      * DynamicDestinationResolver and SimpleMessageConverter.
130      * @see #setDestinationResolver
131      * @see #setMessageConverter
132      * @see org.springframework.jms.support.destination.DynamicDestinationResolver
133      * @see org.springframework.jms.support.converter.SimpleMessageConverter
134      */
135      protected void initDefaultStrategies() {
136 0x          setDestinationResolver(new DynamicDestinationResolver());
137 0x          setMessageConverter(new SimpleMessageConverter());
138 0x      }
139  
140  
141      /**
142      * Set the destination to be used on send/receive operations that do not
143      * have a destination parameter.
144      * <p>Alternatively, specify a "defaultDestinationName", to be
145      * dynamically resolved via the DestinationResolver.
146      * @see #send(MessageCreator)
147      * @see #convertAndSend(Object)
148      * @see #convertAndSend(Object, MessagePostProcessor)
149      * @see #setDefaultDestinationName(String)
150      */
151      public void setDefaultDestination(Destination destination) {
152 0x          this.defaultDestination = destination;
153 0x      }
154  
155      /**
156      * Return the destination to be used on send/receive operations that do not
157      * have a destination parameter.
158      */
159      public Destination getDefaultDestination() {
160 0/2 0x          return (this.defaultDestination instanceof Destination ? (Destination) this.defaultDestination : null);
161      }
162  
163      /**
164      * Set the destination name to be used on send/receive operations that
165      * do not have a destination parameter. The specified name will be
166      * dynamically resolved via the DestinationResolver.
167      * <p>Alternatively, specify a JMS Destination object as "defaultDestination".
168      * @see #send(MessageCreator)
169      * @see #convertAndSend(Object)
170      * @see #convertAndSend(Object, MessagePostProcessor)
171      * @see #setDestinationResolver
172      * @see #setDefaultDestination(javax.jms.Destination)
173      */
174      public void setDefaultDestinationName(String defaultDestinationName) {
175 0x          this.defaultDestination = defaultDestinationName;
176 0x      }
177  
178      /**
179      * Return the destination name to be used on send/receive operations that
180      * do not have a destination parameter.
181      */
182      public String getDefaultDestinationName() {
183 0/2 0x          return (this.defaultDestination instanceof String ? (String) this.defaultDestination : null);
184      }
185  
186      /**
187      * Set the message converter for this template. Used to resolve
188      * Object parameters to convertAndSend methods and Object results
189      * from receiveAndConvert methods.
190      * <p>The default converter is a SimpleMessageConverter, which is able
191      * to handle BytesMessages, TextMessages and ObjectMessages.
192      * @see #convertAndSend
193      * @see #receiveAndConvert
194      * @see org.springframework.jms.support.converter.SimpleMessageConverter
195      */
196      public void setMessageConverter(MessageConverter messageConverter) {
197 0x          this.messageConverter = messageConverter;
198 0x      }
199  
200      /**
201      * Return the message converter for this template.
202      */
203      public MessageConverter getMessageConverter() {
204 0x          return messageConverter;
205      }
206  
207  
208      /**
209      * Set whether message IDs are enabled. Default is "true".
210      * <p>This is only a hint to the JMS producer.
211      * See the JMS javadocs for details.
212      * @see javax.jms.MessageProducer#setDisableMessageID
213      */
214      public void setMessageIdEnabled(boolean messageIdEnabled) {
215 0x          this.messageIdEnabled = messageIdEnabled;
216 0x      }
217  
218      /**
219      * Return whether message IDs are enabled.
220      */
221      public boolean isMessageIdEnabled() {
222 0x          return messageIdEnabled;
223      }
224  
225      /**
226      * Set whether message timestamps are enabled. Default is "true".
227      * <p>This is only a hint to the JMS producer.
228      * See the JMS javadocs for details.
229      * @see javax.jms.MessageProducer#setDisableMessageTimestamp
230      */
231      public void setMessageTimestampEnabled(boolean messageTimestampEnabled) {
232 0x          this.messageTimestampEnabled = messageTimestampEnabled;
233 0x      }
234  
235      /**
236      * Return whether message timestamps are enabled.
237      */
238      public boolean isMessageTimestampEnabled() {
239 0x          return messageTimestampEnabled;
240      }
241  
242      /**
243      * Set whether to inhibit the delivery of messages published by its own connection.
244      * Default is "false".
245      * @see javax.jms.TopicSession#createSubscriber(javax.jms.Topic, String, boolean)
246      */
247      public void setPubSubNoLocal(boolean pubSubNoLocal) {
248 0x          this.pubSubNoLocal = pubSubNoLocal;
249 0x      }
250  
251      /**
252      * Return whether to inhibit the delivery of messages published by its own connection.
253      */
254      public boolean isPubSubNoLocal() {
255 0x          return pubSubNoLocal;
256      }
257  
258      /**
259      * Set the timeout to use for receive calls.
260      * The default is -1, which means no timeout.
261      * @see javax.jms.MessageConsumer#receive(long)
262      * @see javax.jms.MessageConsumer#receive
263      */
264      public void setReceiveTimeout(long receiveTimeout) {
265 0x          this.receiveTimeout = receiveTimeout;
266 0x      }
267  
268      /**
269      * Return the timeout to use for receive calls.
270      */
271      public long getReceiveTimeout() {
272 0x          return receiveTimeout;
273      }
274  
275  
276      /**
277      * Set if the QOS values (deliveryMode, priority, timeToLive)
278      * should be used for sending a message.
279      * @see #setDeliveryMode
280      * @see #setPriority
281      * @see #setTimeToLive
282      */
283      public void setExplicitQosEnabled(boolean explicitQosEnabled) {
284 0x          this.explicitQosEnabled = explicitQosEnabled;
285 0x      }
286  
287      /**
288      * If "true", then the values of deliveryMode, priority, and timeToLive
289      * will be used when sending a message. Otherwise, the default values,
290      * that may be set administratively, will be used.
291      * @return true if overriding default values of QOS parameters
292      * (deliveryMode, priority, and timeToLive)
293      * @see #setDeliveryMode
294      * @see #setPriority
295      * @see #setTimeToLive
296      */
297      public boolean isExplicitQosEnabled() {
298 0x          return explicitQosEnabled;
299      }
300  
301      /**
302      * Set whether message delivery should be persistent or non-persistent,
303      * specified as boolean value ("true" or "false"). This will set the delivery
304      * mode accordingly, to either "PERSISTENT" (1) or "NON_PERSISTENT" (2).
305      * <p>Default it "true" aka delivery mode "PERSISTENT".
306      * @see #setDeliveryMode(int)
307      * @see javax.jms.DeliveryMode#PERSISTENT
308      * @see javax.jms.DeliveryMode#NON_PERSISTENT
309      */
310      public void setDeliveryPersistent(boolean deliveryPersistent) {
311 0/2 0x          this.deliveryMode = (deliveryPersistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
312 0x      }
313  
314      /**
315      * Set the delivery mode to use when sending a message.
316      * Default is the Message default: "PERSISTENT".
317      * <p>Since a default value may be defined administratively,
318      * this is only used when "isExplicitQosEnabled" equals "true".
319      * @param deliveryMode the delivery mode to use
320      * @see #isExplicitQosEnabled
321      * @see javax.jms.DeliveryMode#PERSISTENT
322      * @see javax.jms.DeliveryMode#NON_PERSISTENT
323      * @see javax.jms.Message#DEFAULT_DELIVERY_MODE
324      * @see javax.jms.MessageProducer#send(javax.jms.Message, int, int, long)
325      */
326      public void setDeliveryMode(int deliveryMode) {
327 0x          this.deliveryMode = deliveryMode;
328 0x      }
329  
330      /**
331      * Return the delivery mode to use when sending a message.
332      */
333      public int getDeliveryMode() {
334 0x          return deliveryMode;
335      }
336  
337      /**
338      * Set the priority of a message when sending.
339      * <p>Since a default value may be defined administratively,
340      * this is only used when "isExplicitQosEnabled" equals "true".
341      * @see #isExplicitQosEnabled
342      * @see javax.jms.Message#DEFAULT_PRIORITY
343      * @see javax.jms.MessageProducer#send(javax.jms.Message, int, int, long)
344      */
345      public void setPriority(int priority) {
346 0x          this.priority = priority;
347 0x      }
348  
349      /**
350      * Return the priority of a message when sending.
351      */
352      public int getPriority() {
353 0x          return priority;
354      }
355  
356      /**
357      * Set the time-to-live of the message when sending.
358      * <p>Since a default value may be defined administratively,
359      * this is only used when "isExplicitQosEnabled" equals "true".
360      * @param timeToLive the message's lifetime (in milliseconds)
361      * @see #isExplicitQosEnabled
362      * @see javax.jms.Message#DEFAULT_TIME_TO_LIVE
363      * @see javax.jms.MessageProducer#send(javax.jms.Message, int, int, long)
364      */
365      public void setTimeToLive(long timeToLive) {
366 0x          this.timeToLive = timeToLive;
367 0x      }
368  
369      /**
370      * Return the time-to-live of the message when sending.
371      */
372      public long getTimeToLive() {
373 0x          return timeToLive;
374      }
375  
376  
377      private void checkDefaultDestination() throws IllegalStateException {
378 0/2 0x          if (this.defaultDestination == null) {
379 0x              throw new IllegalStateException(
380                      "No defaultDestination or defaultDestinationName specified. Check configuration of JmsTemplate.");
381          }
382 0x      }
383  
384      private void checkMessageConverter() throws IllegalStateException {
385 0/2 0x          if (getMessageConverter() == null) {
386 0x              throw new IllegalStateException("No messageConverter registered. Check configuration of JmsTemplate.");
387          }
388 0x      }
389  
390  
391      /**
392      * Execute the action specified by the given action object within a
393      * JMS Session. Generalized version of <code>execute(SessionCallback)</code>,
394      * allowing to start the JMS Connection on the fly.
395      * <p>Use <code>execute(SessionCallback)</code> for the general case.
396      * Starting the JMS Connection is just necessary for receiving messages,
397      * which is preferably achieve through the <code>receive</code> methods.
398      * @param action callback object that exposes the session
399      * @return the result object from working with the session
400      * @throws JmsException if there is any problem
401      * @see #execute(SessionCallback)
402      * @see #receive
403      */
404      public Object execute(SessionCallback action, boolean startConnection) throws JmsException {
405 0x          Connection con = null;
406 0x          Session session = null;
407          try {
408 0x              Connection conToUse = null;
409 0x              Session sessionToUse = null;
410 0x              ConnectionHolder conHolder =
411                      (ConnectionHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
412 0/2 0x              if (conHolder != null) {
413 0x                  conToUse = conHolder.getConnection();
414 0/2 0x                  if (startConnection) {
415 0x                      conToUse.start();
416                  }
417 0x                  sessionToUse = conHolder.getSession();
418 0x              }
419              else {
420 0x                  con = createConnection();
421 0/2 0x                  if (startConnection) {
422 0x                      con.start();
423                  }
424 0x                  session = createSession(con);
425 0x                  conToUse = con;
426 0x                  sessionToUse = session;
427              }
428 0/2 0x              if (logger.isDebugEnabled()) {
429 0x                  logger.debug("Executing callback on JMS Session [" + sessionToUse +
430                          "] from connection [" + conToUse + "]");
431              }
432 0x              return action.doInJms(sessionToUse);
433          }
434 0x          catch (JMSException ex) {
435 0x              throw convertJmsAccessException(ex);
436          }
437          finally {
438 0x              JmsUtils.closeSession(session);
439 0x              JmsUtils.closeConnection(con);
440 0x          }
441      }
442  
443      public Object execute(SessionCallback action) throws JmsException {
444 0x          return execute(action, false);
445      }
446  
447      public Object execute(final ProducerCallback action) throws JmsException {
448 0x          return execute(new SessionCallback() {
449              public Object doInJms(Session session) throws JMSException {
450                  MessageProducer producer = createProducer(session, null);
451                  try {
452                      return action.doInJms(session, producer);
453                  }
454                  finally {
455                      JmsUtils.closeMessageProducer(producer);
456                  }
457              }
458          }, false);
459      }
460  
461  
462      //-------------------------------------------------------------------------
463      // Convenience methods for sending messages
464      //-------------------------------------------------------------------------
465  
466      public void send(MessageCreator messageCreator) throws JmsException {
467 0x          checkDefaultDestination();
468 0/2 0x          if (getDefaultDestination() != null) {
469 0x              send(getDefaultDestination(), messageCreator);
470 0x          }
471          else {
472 0x              send(getDefaultDestinationName(), messageCreator);
473          }
474 0x      }
475  
476      public void send(final Destination destination, final MessageCreator messageCreator) throws JmsException {
477 0x          execute(new SessionCallback() {
478              public Object doInJms(Session session) throws JMSException {
479                  doSend(session, destination, messageCreator);
480                  return null;
481              }
482          }, false);
483 0x      }
484  
485      public void send(final String destinationName, final MessageCreator messageCreator) throws JmsException {
486 0x          execute(new SessionCallback() {
487              public Object doInJms(Session session) throws JMSException {
488                  Destination destination = resolveDestinationName(session, destinationName);
489                  doSend(session, destination, messageCreator);
490                  return null;
491              }
492          }, false);
493 0x      }
494  
495      protected void doSend(Session session, Destination destination, MessageCreator messageCreator)
496              throws JMSException {
497  
498 0x          MessageProducer producer = createProducer(session, destination);
499          try {
500 0x              Message message = messageCreator.createMessage(session);
501 0/2 0x              if (logger.isDebugEnabled()) {
502 0x                  logger.debug("Sending created message [" + message + "]");
503              }
504 0x              doSend(producer, message);
505              // Check commit - avoid commit call within a JTA transaction.
506 0/6 0x              if (session.getTransacted() && isSessionTransacted() &&
507                      !TransactionSynchronizationManager.hasResource(getConnectionFactory())) {
508                  // Transacted session created by this template -> commit.
509 0x                  JmsUtils.commitIfNecessary(session);
510              }
511          }
512          finally {
513 0x              JmsUtils.closeMessageProducer(producer);
514 0x          }
515 0x      }
516  
517      protected void doSend(MessageProducer producer, Message message) throws JMSException {
518 0/2 0x          if (isExplicitQosEnabled()) {
519 0x              producer.send(message, getDeliveryMode(), getPriority(), getTimeToLive());
520 0x          }
521          else {
522 0x              producer.send(message);
523          }
524 0x      }
525  
526  
527      //-------------------------------------------------------------------------
528      // Convenience methods for sending auto-converted messages
529      //-------------------------------------------------------------------------
530  
531      public void convertAndSend(Object message) throws JmsException {
532 0x          checkDefaultDestination();
533 0/2 0x          if (getDefaultDestination() != null) {
534 0x              convertAndSend(getDefaultDestination(), message);
535 0x          }
536          else {
537 0x              convertAndSend(getDefaultDestinationName(), message);
538          }
539 0x      }
540  
541      public void convertAndSend(Destination destination, final Object message) throws JmsException {
542 0x          checkMessageConverter();
543 0x          send(destination, new MessageCreator() {
544              public Message createMessage(Session session) throws JMSException {
545                  return getMessageConverter().toMessage(message, session);
546              }
547          });
548 0x      }
549  
550      public void convertAndSend(String destinationName, final Object message) throws JmsException {
551 0x          checkMessageConverter();
552 0x          send(destinationName, new MessageCreator() {
553              public Message createMessage(Session session) throws JMSException {
554                  return getMessageConverter().toMessage(message, session);
555              }
556          });
557 0x      }
558  
559      public void convertAndSend(Object message, MessagePostProcessor postProcessor) throws JmsException {
560 0x          checkDefaultDestination();
561 0/2 0x          if (getDefaultDestination() != null) {
562 0x              convertAndSend(getDefaultDestination(), message, postProcessor);
563 0x          }
564          else {
565 0x              convertAndSend(getDefaultDestinationName(), message, postProcessor);
566          }
567 0x      }
568  
569      public void convertAndSend(
570              Destination destination, final Object message, final MessagePostProcessor postProcessor)
571              throws JmsException {
572  
573 0x          checkMessageConverter();
574 0x          send(destination, new MessageCreator() {
575              public Message createMessage(Session session) throws JMSException {
576                  Message msg = getMessageConverter().toMessage(message, session);
577                  return postProcessor.postProcessMessage(msg);
578              }
579          });
580 0x      }
581  
582      public void convertAndSend(
583              String destinationName, final Object message, final MessagePostProcessor postProcessor)
584          throws JmsException {
585  
586 0x          checkMessageConverter();
587 0x          send(destinationName, new MessageCreator() {
588              public Message createMessage(Session session) throws JMSException {
589                  Message msg = getMessageConverter().toMessage(message, session);
590                  return postProcessor.postProcessMessage(msg);
591              }
592          });
593 0x      }
594  
595  
596      //-------------------------------------------------------------------------
597      // Convenience methods for receiving messages
598      //-------------------------------------------------------------------------
599  
600      public Message receive() throws JmsException {
601 0x          checkDefaultDestination();
602 0/2 0x          if (getDefaultDestination() != null) {
603 0x              return receive(getDefaultDestination());
604          }
605          else {
606 0x              return receive(getDefaultDestinationName());
607          }
608      }
609  
610      public Message receive(final Destination destination) throws JmsException {
611 0x          return (Message) execute(new SessionCallback() {
612              public Object doInJms(Session session) throws JMSException {
613                  return doReceive(session, destination, null);
614              }
615          }, true);
616      }
617  
618      public Message receive(final String destinationName) throws JmsException {
619 0x          return (Message) execute(new SessionCallback() {
620              public Object doInJms(Session session) throws JMSException {
621                  Destination destination = resolveDestinationName(session, destinationName);
622                  return doReceive(session, destination, null);
623              }
624          }, true);
625      }
626  
627      public Message receiveSelected(String messageSelector) throws JmsException {
628 0x          checkDefaultDestination();
629 0/2 0x          if (getDefaultDestination() != null) {
630 0x              return receiveSelected(getDefaultDestination(), messageSelector);
631          }
632          else {
633 0x              return receiveSelected(getDefaultDestinationName(), messageSelector);
634          }
635      }
636  
637      public Message receiveSelected(final Destination destination, final String messageSelector) throws JmsException {
638 0x          return (Message) execute(new SessionCallback() {
639              public Object doInJms(Session session) throws JMSException {
640                  return doReceive(session, destination, messageSelector);
641              }
642          }, true);
643      }
644  
645      public Message receiveSelected(final String destinationName, final String messageSelector) throws JmsException {
646 0x          return (Message) execute(new SessionCallback() {
647              public Object doInJms(Session session) throws JMSException {
648                  Destination destination = resolveDestinationName(session, destinationName);
649                  return doReceive(session, destination, messageSelector);
650              }
651          }, true);
652      }
653  
654      protected Message doReceive(Session session, Destination destination, String messageSelector)
655              throws JMSException {
656  
657 0x          return doReceive(session, createConsumer(session, destination, messageSelector));
658      }
659  
660      protected Message doReceive(Session session, MessageConsumer consumer) throws JMSException {
661          try {
662              // Use transaction timeout (if available).
663 0x              long timeout = getReceiveTimeout();
664 0x              ConnectionHolder conHolder =
665                      (ConnectionHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
666 0/4 0x              if (conHolder != null && conHolder.hasTimeout()) {
667 0x                  timeout = conHolder.getTimeToLiveInMillis();
668              }
669 0/2 0x              Message message = (timeout >= 0) ?
670                      consumer.receive(timeout) : consumer.receive();
671 0/2 0x              if (session.getTransacted()) {
672                  // Commit necessary - but avoid commit call within a JTA transaction.
673 0/4 0x                  if (isSessionTransacted() && conHolder == null) {
674                      // Transacted session created by this template -> commit.
675 0x                      JmsUtils.commitIfNecessary(session);
676 0x                  }
677              }
678 0/2 0x              else if (isClientAcknowledge(session)) {
679                  // Manually acknowledge message, if any.
680 0/2 0x                  if (message != null) {
681 0x                      message.acknowledge();
682                  }
683              }
684 0x              return message;
685          }
686          finally {
687 0x              JmsUtils.closeMessageConsumer(consumer);
688 0x          }
689      }
690  
691      /**
692      * Return whether the Session is in client acknowledge mode.
693      * <p>This implementation uses JMS 1.1 API.
694      * @param session the JMS Session to check
695      * @throws JMSException if thrown by JMS API methods
696      */
697      protected boolean isClientAcknowledge(Session session) throws JMSException {
698 0/2 0x          return (session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
699      }
700  
701  
702      //-------------------------------------------------------------------------
703      // Convenience methods for receiving auto-converted messages
704      //-------------------------------------------------------------------------
705  
706      public Object receiveAndConvert() throws JmsException {
707 0x          checkMessageConverter();
708 0x          return doConvertFromMessage(receive());
709      }
710  
711      public Object receiveAndConvert(Destination destination) throws JmsException {
712 0x          checkMessageConverter();
713 0x          return doConvertFromMessage(receive(destination));
714      }
715  
716      public Object receiveAndConvert(String destinationName) throws JmsException {
717 0x          checkMessageConverter();
718 0x          return doConvertFromMessage(receive(destinationName));
719      }
720  
721      public Object receiveSelectedAndConvert(String messageSelector) throws JmsException {
722 0x          checkMessageConverter();
723 0x          return doConvertFromMessage(receiveSelected(messageSelector));
724      }
725  
726      public Object receiveSelectedAndConvert(Destination destination, String messageSelector) throws JmsException {
727 0x          checkMessageConverter();
728 0x          return doConvertFromMessage(receiveSelected(destination, messageSelector));
729      }
730  
731      public Object receiveSelectedAndConvert(String destinationName, String messageSelector) throws JmsException {
732 0x          checkMessageConverter();
733 0x          return doConvertFromMessage(receiveSelected(destinationName, messageSelector));
734      }
735  
736      protected Object doConvertFromMessage(Message message) {
737 0/2 0x          if (message != null) {
738              try {
739 0x                  return getMessageConverter().fromMessage(message);
740              }
741 0x              catch (JMSException ex) {
742 0x                  throw convertJmsAccessException(ex);
743              }
744          }
745 0x          return null;
746      }
747  
748  
749      //-------------------------------------------------------------------------
750      // JMS 1.1 factory methods, potentially overridden for JMS 1.0.2
751      //-------------------------------------------------------------------------
752  
753      /**
754      * Create a JMS Connection via this template's ConnectionFactory.
755      * <p>This implementation uses JMS 1.1 API.
756      * @return the new JMS Connection
757      * @throws JMSException if thrown by JMS API methods
758      */
759      protected Connection createConnection() throws JMSException {
760 0x          return getConnectionFactory().createConnection();
761      }
762  
763      /**
764      * Create a JMS Session for the given Connection.
765      * <p>This implementation uses JMS 1.1 API.
766      * @param con the JMS Connection to create a Session for
767      * @return the new JMS Session
768      * @throws JMSException if thrown by JMS API methods
769      */
770      protected Session createSession(Connection con) throws JMSException {
771 0x          return con.createSession(isSessionTransacted(), getSessionAcknowledgeMode());
772      }
773  
774      /**
775      * Create a JMS MessageProducer for the given Session and Destination,
776      * configuring it to disable message ids and/or timestamps (if necessary).
777      * <p>Delegates to <code>doCreateProducer</code> for creation of the raw
778      * JMS MessageProducer, which needs to be specific to JMS 1.1 or 1.0.2.
779      * @param session the JMS Session to create a MessageProducer for
780      * @param destination the JMS Destination to create a MessageProducer for
781      * @return the new JMS MessageProducer
782      * @throws JMSException if thrown by JMS API methods
783      * @see #doCreateProducer
784      * @see #setMessageIdEnabled
785      * @see #setMessageTimestampEnabled
786      */
787      protected MessageProducer createProducer(Session session, Destination destination) throws JMSException {
788 0x          MessageProducer producer = doCreateProducer(session, destination);
789 0/2 0x          if (!isMessageIdEnabled()) {
790 0x              producer.setDisableMessageID(true);
791          }
792 0/2 0x          if (!isMessageTimestampEnabled()) {
793 0x              producer.setDisableMessageTimestamp(true);
794          }
795 0x          return producer;
796      }
797  
798      /**
799      * Create a raw JMS MessageProducer for the given Session and Destination.
800      * <p>This implementation uses JMS 1.1 API.
801      * @param session the JMS Session to create a MessageProducer for
802      * @param destination the JMS Destination to create a MessageProducer for
803      * @return the new JMS MessageProducer
804      * @throws JMSException if thrown by JMS API methods
805      */
806      protected MessageProducer doCreateProducer(Session session, Destination destination) throws JMSException {
807 0x          return session.createProducer(destination);
808      }
809  
810      /**
811      * Create a JMS MessageConsumer for the given Session and Destination.
812      * <p>This implementation uses JMS 1.1 API.
813      * @param session the JMS Session to create a MessageConsumer for
814      * @param destination the JMS Destination to create a MessageConsumer for
815      * @param messageSelector the message selector for this consumer (can be <code>null</code>)
816      * @return the new JMS MessageConsumer
817      * @throws JMSException if thrown by JMS API methods
818      */
819      protected MessageConsumer createConsumer(Session session, Destination destination, String messageSelector)
820              throws JMSException {
821  
822          // Only pass in the NoLocal flag in case of a Topic:
823          // Some JMS providers, such as WebSphere MQ 6.0, throw IllegalStateException
824          // in case of the NoLocal flag being specified for a Queue.
825 0/2 0x          if (destination instanceof Topic) {
826 0x              return session.createConsumer(destination, messageSelector, isPubSubNoLocal());
827          }
828          else {
829 0x              return session.createConsumer(destination, messageSelector);
830          }
831      }
832  
833  }