JmsTemplate.java
Upload User: jiancairen
Upload Date: 2007-08-27
Package Size: 26458k
Code Size: 26k
Category:

Java Develop

Development Platform:

Java

  1. /*
  2.  * Copyright 2002-2004 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. package org.springframework.jms.core;
  17. import javax.jms.Connection;
  18. import javax.jms.ConnectionFactory;
  19. import javax.jms.Destination;
  20. import javax.jms.JMSException;
  21. import javax.jms.Message;
  22. import javax.jms.MessageConsumer;
  23. import javax.jms.MessageProducer;
  24. import javax.jms.Session;
  25. import org.apache.commons.logging.Log;
  26. import org.apache.commons.logging.LogFactory;
  27. import org.springframework.beans.factory.InitializingBean;
  28. import org.springframework.core.Constants;
  29. import org.springframework.jms.JmsException;
  30. import org.springframework.jms.connection.ConnectionHolder;
  31. import org.springframework.jms.support.JmsUtils;
  32. import org.springframework.jms.support.converter.MessageConverter;
  33. import org.springframework.jms.support.converter.SimpleMessageConverter;
  34. import org.springframework.jms.support.destination.DestinationResolver;
  35. import org.springframework.jms.support.destination.DynamicDestinationResolver;
  36. import org.springframework.transaction.support.TransactionSynchronizationManager;
  37. /**
  38.  * Helper class that simplifies JMS access code. This class requires a
  39.  * JMS 1.1 provider, because it builds on the new domain-independent API.
  40.  * <b>Use the {@link JmsTemplate102 JmsTemplate102} subclass for
  41.  * JMS 1.0.2 providers.</b>
  42.  *
  43.  * <p>If you want to use dynamic destination creation, you must specify
  44.  * the type of JMS destination to create, using the "pubSubDomain" property.
  45.  * For other operations, this is not necessary, in contrast to when working
  46.  * with JmsTemplate102. Point-to-Point (Queues) is the default domain.
  47.  *
  48.  * <p>Default settings for JMS sessions are not transacted and auto-acknowledge.
  49.  * As defined by the J2EE specification, the transaction and acknowledgement
  50.  * parameters are ignored when a JMS Session is created inside an active
  51.  * transaction, no matter if a JTA transaction or a Spring-managed transaction.
  52.  *
  53.  * <p>This template uses a DynamicDestinationResolver and a SimpleMessageConverter
  54.  * as default strategies for resolving a destination name respectively converting
  55.  * a message.
  56.  *
  57.  * @author Mark Pollack
  58.  * @author Juergen Hoeller
  59.  * @since 1.1
  60.  * @see #setConnectionFactory
  61.  * @see #setPubSubDomain
  62.  * @see JmsTemplate102
  63.  * @see #setDestinationResolver
  64.  * @see #setMessageConverter
  65.  * @see org.springframework.jms.support.destination.DynamicDestinationResolver
  66.  * @see org.springframework.jms.support.converter.SimpleMessageConverter
  67.  */
  68. public class JmsTemplate implements JmsOperations, InitializingBean {
  69. /**
  70.  * Default timeout for receive operations:
  71.  * -1 indicates a blocking receive without timeout.
  72.  */
  73. public static final long DEFAULT_RECEIVE_TIMEOUT = -1;
  74. /** Constants instance for javax.jms.Session */
  75. private static final Constants constants = new Constants(Session.class);
  76. protected final Log logger = LogFactory.getLog(getClass());
  77. /**
  78.  * Used to obtain JMS connections.
  79.  */
  80. private ConnectionFactory connectionFactory;
  81. /**
  82.  * By default uses the Point-to-Point domain.
  83.  */
  84. private boolean pubSubDomain = false;
  85. /**
  86.  * Default transaction mode for a JMS Session.
  87.  */
  88. private boolean sessionTransacted = false;
  89. /**
  90.  * Default ack mode for a JMS Session.
  91.  */
  92. private int sessionAcknowledgeMode = Session.AUTO_ACKNOWLEDGE;
  93. /**
  94.  * The default destination to use on send operations that do not specify an explicit destination.
  95.  */
  96. private Destination defaultDestination;
  97. /**
  98.  * Delegate management of JNDI lookups and dynamic destination creation
  99.  * to a DestinationResolver implementation.
  100.  */
  101. private DestinationResolver destinationResolver;
  102. /**
  103.  * The messageConverter to use for send(object) methods.
  104.  */
  105. private MessageConverter messageConverter;
  106. /**
  107.  * The timeout to use for receive operations.
  108.  */
  109. private long receiveTimeout = DEFAULT_RECEIVE_TIMEOUT;
  110. /**
  111.  * Use the default or explicit QOS parameters.
  112.  */
  113. private boolean explicitQosEnabled;
  114. /**
  115.  * The delivery mode to use when sending a message. Only used if isExplicitQosEnabled = true.
  116.  */
  117. private int deliveryMode;
  118. /**
  119.  * The priority of the message. Only used if isExplicitQosEnabled = true.
  120.  */
  121. private int priority;
  122. /**
  123.  * The message's lifetime in milliseconds. Only used if isExplicitQosEnabled = true.
  124.  */
  125. private long timeToLive;
  126. /**
  127.  * Create a new JmsTemplate for bean-style usage.
  128.  * <p>Note: The ConnectionFactory has to be set before using the instance.
  129.  * This constructor can be used to prepare a JmsTemplate via a BeanFactory,
  130.  * typically setting the ConnectionFactory via setConnectionFactory.
  131.  * @see #setConnectionFactory
  132.  */
  133. public JmsTemplate() {
  134. initDefaultStrategies();
  135. }
  136. /**
  137.  * Create a new JmsTemplate, given a ConnectionFactory.
  138.  * @param connectionFactory the ConnectionFactory to obtain connections from
  139.  */
  140. public JmsTemplate(ConnectionFactory connectionFactory) {
  141. this();
  142. setConnectionFactory(connectionFactory);
  143. afterPropertiesSet();
  144. }
  145. /**
  146.  * Initialize the default implementations for the template's strategies:
  147.  * DynamicDestinationResolver and SimpleMessageConverter.
  148.  * @see #setDestinationResolver
  149.  * @see #setMessageConverter
  150.  * @see org.springframework.jms.support.destination.DynamicDestinationResolver
  151.  * @see org.springframework.jms.support.converter.SimpleMessageConverter
  152.  */
  153. protected void initDefaultStrategies() {
  154. setDestinationResolver(new DynamicDestinationResolver());
  155. setMessageConverter(new SimpleMessageConverter());
  156. }
  157. /**
  158.  * Set the connection factory used for obtaining JMS connections.
  159.  */
  160. public void setConnectionFactory(ConnectionFactory connectionFactory) {
  161. this.connectionFactory = connectionFactory;
  162. }
  163.     
  164. /**
  165.  * Return the connection factory used for obtaining JMS connections.
  166.  */
  167. public ConnectionFactory getConnectionFactory() {
  168. return connectionFactory;
  169. }
  170. /**
  171.  * Configure the JmsTemplate with knowledge of the JMS domain used.
  172.  * Default is Point-to-Point (Queues).
  173.  * <p>For JmsTemplate102, this tells the JMS provider which class hierarchy to use
  174.  * in the implementation of the various execute methods. For JmsTemplate itself,
  175.  * it does not affect execute methods. In both implementations, it tells what type
  176.  * of destination to create if dynamic destinations are enabled.
  177.  * @param pubSubDomain true for Publish/Subscribe domain (Topics),
  178.  * false for Point-to-Point domain (Queues)
  179.  * @see #setDestinationResolver
  180.  */
  181. public void setPubSubDomain(boolean pubSubDomain) {
  182. this.pubSubDomain = pubSubDomain;
  183. }
  184. /**
  185.  * Return whether the Publish/Subscribe domain (Topics) is used.
  186.  * Otherwise, the Point-to-Point domain (Queues) is used.
  187.  */
  188. public boolean isPubSubDomain() {
  189. return pubSubDomain;
  190. }
  191. /**
  192.  * Set the transaction mode that is used when creating a JMS session to send a message.
  193.  * <p>Note that that within a JTA transaction, the parameters to
  194.  * create<Queue|Topic>Session(boolean transacted, int acknowledgeMode) method are not
  195.  * taken into account. Depending on the J2EE transaction context, the container
  196.  * makes its own decisions on these values. See section 17.3.5 of the EJB Spec.
  197.  * @param sessionTransacted the transaction mode
  198.  */
  199. public void setSessionTransacted(boolean sessionTransacted) {
  200. this.sessionTransacted = sessionTransacted;
  201. }
  202. /**
  203.  * Return whether the JMS sessions used for sending a message are transacted.
  204.  */
  205. public boolean isSessionTransacted() {
  206. return sessionTransacted;
  207. }
  208. /**
  209.  * Set the JMS acknowledgement mode by the name of the corresponding constant
  210.  * in the JMS Session interface, e.g. "CLIENT_ACKNOWLEDGE".
  211.  * @param constantName name of the constant
  212.  * @see javax.jms.Session#AUTO_ACKNOWLEDGE
  213.  * @see javax.jms.Session#CLIENT_ACKNOWLEDGE
  214.  * @see javax.jms.Session#DUPS_OK_ACKNOWLEDGE
  215.  */
  216. public void setSessionAcknowledgeModeName(String constantName) {
  217. setSessionAcknowledgeMode(constants.asNumber(constantName).intValue());
  218. }
  219. /**
  220.  * Set the JMS acknowledgement mode that is used when creating a JMS session to send
  221.  * a message. Vendor extensions to the acknowledgment mode can be set here as well.
  222.  * <p>Note that that inside an EJB the parameters to
  223.  * create<Queue|Topic>Session(boolean transacted, int acknowledgeMode) method are not
  224.  * taken into account. Depending on the transaction context in the EJB, the container
  225.  * makes its own decisions on these values. See section 17.3.5 of the EJB Spec.
  226.  * @param sessionAcknowledgeMode the acknowledgement mode
  227.  */
  228. public void setSessionAcknowledgeMode(int sessionAcknowledgeMode) {
  229. this.sessionAcknowledgeMode = sessionAcknowledgeMode;
  230. }
  231. /**
  232.  * Return the acknowledgement mode for JMS sessions.
  233.  */
  234. public int getSessionAcknowledgeMode() {
  235. return sessionAcknowledgeMode;
  236. }
  237. /**
  238.  * Set the destination to be used on send operations that do not
  239.  * have a destination parameter.
  240.  * @see #send(MessageCreator)
  241.  * @see #convertAndSend(Object)
  242.  * @see #convertAndSend(Object, MessagePostProcessor)
  243.  */
  244. public void setDefaultDestination(Destination destination) {
  245. this.defaultDestination = destination;
  246. }
  247. /**
  248.  * Return the destination to be used on send operations that do not
  249.  * have a destination parameter.
  250.  */
  251. public Destination getDefaultDestination() {
  252. return defaultDestination;
  253. }
  254. /**
  255.  * Set the destination resolver for this template. Used to resolve
  256.  * destination names and to support dynamic destination functionality.
  257.  * <p>The default resolver is a DynamicDestinationResolver. Specify a
  258.  * JndiDestinationResolver for resolving destination names as JNDI locations.
  259.  * @see org.springframework.jms.support.destination.DynamicDestinationResolver
  260.  * @see org.springframework.jms.support.destination.JndiDestinationResolver
  261.  */
  262. public void setDestinationResolver(DestinationResolver destinationResolver) {
  263. this.destinationResolver = destinationResolver;
  264. }
  265. /**
  266.  * Get the destination resolver for this template.
  267.  */
  268. public DestinationResolver getDestinationResolver() {
  269. return destinationResolver;
  270. }
  271. /**
  272.  * Set the message converter for this template. Used to resolve
  273.  * Object parameters to convertAndSend methods and Object results
  274.  * from receiveAndConvert methods.
  275.  * <p>The default converter is a SimpleMessageConverter, which is able
  276.  * to handle BytesMessages, TextMessages and ObjectMessages.
  277.  * @see #convertAndSend
  278.  * @see #receiveAndConvert
  279.  * @see org.springframework.jms.support.converter.SimpleMessageConverter
  280.  */
  281. public void setMessageConverter(MessageConverter messageConverter) {
  282. this.messageConverter = messageConverter;
  283. }
  284. /**
  285.  * Return the message converter for this template.
  286.  */
  287. public MessageConverter getMessageConverter() {
  288. return messageConverter;
  289. }
  290. /**
  291.  * Set the timeout to use for receive calls.
  292.  * The default is -1, which means no timeout.
  293.  * @see javax.jms.MessageConsumer#receive(long)
  294.  * @see javax.jms.MessageConsumer#receive
  295.  */
  296. public void setReceiveTimeout(long receiveTimeout) {
  297. this.receiveTimeout = receiveTimeout;
  298. }
  299. /**
  300.  * Return the timeout to use for receive calls.
  301.  */
  302. public long getReceiveTimeout() {
  303. return receiveTimeout;
  304. }
  305. /**
  306.  * Set if the QOS values (deliveryMode, priority, timeToLive)
  307.  * should be used for sending a message.
  308.  */
  309. public void setExplicitQosEnabled(boolean explicitQosEnabled) {
  310. this.explicitQosEnabled = explicitQosEnabled;
  311. }
  312. /**
  313.  * If true, then the values of deliveryMode, priority, and timeToLive
  314.  * will be used when sending a message. Otherwise, the default values,
  315.  * that may be set administratively, will be used.
  316.  * @return true if overriding default values of QOS parameters
  317.  * (deliveryMode, priority, and timeToLive)
  318.  * @see #setDeliveryMode
  319.  * @see #setPriority
  320.  * @see #setTimeToLive
  321.  */
  322. public boolean isExplicitQosEnabled() {
  323. return explicitQosEnabled;
  324. }
  325. /**
  326.  * Set the delivery mode to use when sending a message. Since a default value may be
  327.  * defined administratively, it is only used when isExplicitQosEnabled equals true.
  328.  * @param deliveryMode the delivery mode to use
  329.  * @see #isExplicitQosEnabled
  330.  */
  331. public void setDeliveryMode(int deliveryMode) {
  332. this.deliveryMode = deliveryMode;
  333. }
  334. /**
  335.  * Return the delivery mode to use when sending a message.
  336.  */
  337. public int getDeliveryMode() {
  338. return deliveryMode;
  339. }
  340. /**
  341.  * Set the priority of a message when sending. Since a default value may be defined
  342.  * administratively, it is only used when isExplicitQosEnabled equals true.
  343.  * @see #isExplicitQosEnabled
  344.  */
  345. public void setPriority(int priority) {
  346. this.priority = priority;
  347. }
  348. /**
  349.  * Return the priority of a message when sending.
  350.  */
  351. public int getPriority() {
  352. return priority;
  353. }
  354. /**
  355.  * Set the time-to-live of the message when sending. Since a default value may be
  356.  * defined administratively, it is only used when isExplicitQosEnabled equals true.
  357.  * @param timeToLive the message's lifetime (in milliseconds)
  358.  * @see #isExplicitQosEnabled
  359.  */
  360. public void setTimeToLive(long timeToLive) {
  361. this.timeToLive = timeToLive;
  362. }
  363. /**
  364.  * Return the time-to-live of the message when sending.
  365.  */
  366. public long getTimeToLive() {
  367. return timeToLive;
  368. }
  369. /**
  370.  * Make sure the connection factory has been set.
  371.  */
  372. public void afterPropertiesSet() {
  373. if (this.connectionFactory == null) {
  374. throw new IllegalArgumentException("connectionFactory is required");
  375. }
  376. }
  377. /**
  378.  * Create a JMS Connection via this template's ConnectionFactory.
  379.  * <p>This implementation uses JMS 1.1 API.
  380.  * @return the new JMS Connection
  381.  * @throws JMSException if thrown by JMS API methods
  382.  */
  383. protected Connection createConnection() throws JMSException {
  384. return getConnectionFactory().createConnection();
  385. }
  386. /**
  387.  * Create a JMS Session for the given Connection.
  388.  * <p>This implementation uses JMS 1.1 API.
  389.  * @param con the JMS Connection to create a Session for
  390.  * @return the new JMS Session
  391.  * @throws JMSException if thrown by JMS API methods
  392.  */
  393. protected Session createSession(Connection con) throws JMSException {
  394. return con.createSession(isSessionTransacted(), getSessionAcknowledgeMode());
  395. }
  396. /**
  397.  * Create a JMS MessageProducer for the given Session and Destination.
  398.  * <p>This implementation uses JMS 1.1 API.
  399.  * @param session the JMS Session to create a MessageProducer for
  400.  * @param destination the JMS Destination to create a MessageProducer for
  401.  * @return the new JMS MessageProducer
  402.  * @throws JMSException if thrown by JMS API methods
  403.  */
  404. protected MessageProducer createProducer(Session session, Destination destination) throws JMSException {
  405. return session.createProducer(destination);
  406. }
  407. /**
  408.  * Create a JMS MessageConsumer for the given Session and Destination.
  409.  * <p>This implementation uses JMS 1.1 API.
  410.  * @param session the JMS Session to create a MessageConsumer for
  411.  * @param destination the JMS Destination to create a MessageConsumer for
  412.  * @return the new JMS MessageConsumer
  413.  * @throws JMSException if thrown by JMS API methods
  414.  */
  415. protected MessageConsumer createConsumer(Session session, Destination destination) throws JMSException {
  416. return session.createConsumer(destination);
  417. }
  418. /**
  419.  * Resolve the given destination name into a JMS Destination,
  420.  * via this template's DestinationResolver.
  421.  * @param session the current JMS Session
  422.  * @param destinationName the name of the destination
  423.  * @return the located Destination
  424.  * @throws JMSException if resolution failed
  425.  * @see #setDestinationResolver
  426.  */
  427. protected Destination resolveDestinationName(Session session, String destinationName) throws JMSException {
  428. return getDestinationResolver().resolveDestinationName(session, destinationName, isPubSubDomain());
  429. }
  430. /**
  431.  * Convert the specified checked {@link javax.jms.JMSException JMSException} to
  432.  * a Spring runtime {@link org.springframework.jms.JmsException JmsException}
  433.  * equivalent.
  434.  * <p>Default implementation delegates to JmsUtils.
  435.  * @param ex the original checked JMSException to convert
  436.  * @return the Spring runtime JmsException wrapping <code>ex</code>
  437.  * @see org.springframework.jms.support.JmsUtils#convertJmsAccessException
  438.  */
  439. protected JmsException convertJmsAccessException(JMSException ex) {
  440. return JmsUtils.convertJmsAccessException(ex);
  441. }
  442. /**
  443.  * Execute the action specified by the given action object within a
  444.  * JMS Session. Generalized version of execute(SessionCallback),
  445.  * allowing to start the JMS Connection on the fly.
  446.  * <p>Use execute(SessionCallback) for the general case. Starting
  447.  * the JMS Connection is just necessary for receiving messages,
  448.  * which is preferably achieve through the <code>receive</code> methods.
  449.  * @param action callback object that exposes the session
  450.  * @return the result object from working with the session
  451.  * @throws JmsException if there is any problem
  452.  * @see #execute(SessionCallback)
  453.  * @see #receive
  454.  */
  455. public Object execute(SessionCallback action, boolean startConnection) throws JmsException {
  456. Connection con = null;
  457. Session session = null;
  458. try {
  459. Connection conToUse = null;
  460. Session sessionToUse = null;
  461. ConnectionHolder conHolder =
  462. (ConnectionHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
  463. if (conHolder != null) {
  464. conToUse = conHolder.getConnection();
  465. if (startConnection) {
  466. conToUse.start();
  467. }
  468. sessionToUse = conHolder.getSession();
  469. }
  470. else {
  471. con = createConnection();
  472. if (startConnection) {
  473. con.start();
  474. }
  475. session = createSession(con);
  476. conToUse = con;
  477. sessionToUse = session;
  478. }
  479. if (logger.isDebugEnabled()) {
  480. logger.debug("Executing callback on JMS session [" + sessionToUse + "] from connection [" + conToUse + "]");
  481. }
  482. return action.doInJms(sessionToUse);
  483. }
  484. catch (JMSException ex) {
  485. throw convertJmsAccessException(ex);
  486. }
  487. finally {
  488. JmsUtils.closeSession(session);
  489. JmsUtils.closeConnection(con);
  490. }
  491. }
  492. public Object execute(SessionCallback action) throws JmsException {
  493. return execute(action, false);
  494. }
  495. public Object execute(final ProducerCallback action) throws JmsException {
  496. return execute(new SessionCallback() {
  497. public Object doInJms(Session session) throws JMSException {
  498. MessageProducer producer = createProducer(session, null);
  499. return action.doInJms(session, producer);
  500. }
  501. });
  502. }
  503. public void send(MessageCreator messageCreator) throws JmsException {
  504. if (getDefaultDestination() == null) {
  505. throw new IllegalStateException("No defaultDestination specified. Check configuration of JmsTemplate.");
  506. }
  507. send(getDefaultDestination(), messageCreator);
  508. }
  509. public void send(final Destination destination, final MessageCreator messageCreator) throws JmsException {
  510. execute(new SessionCallback() {
  511. public Object doInJms(Session session) throws JMSException {
  512. doSend(session, destination, messageCreator);
  513. return null;
  514. }
  515. });
  516. }
  517. public void send(final String destinationName, final MessageCreator messageCreator) throws JmsException {
  518. execute(new SessionCallback() {
  519. public Object doInJms(Session session) throws JMSException {
  520. Destination destination = resolveDestinationName(session, destinationName);
  521. doSend(session, destination, messageCreator);
  522. return null;
  523. }
  524. });
  525. }
  526. protected void doSend(Session session, Destination destination, MessageCreator messageCreator)
  527. throws JMSException {
  528. MessageProducer producer = createProducer(session, destination);
  529. Message message = messageCreator.createMessage(session);
  530. if (logger.isDebugEnabled()) {
  531. logger.debug("Sending created message [" + message + "]");
  532. }
  533. doSend(producer, message);
  534. if (session.getTransacted() && !TransactionSynchronizationManager.hasResource(getConnectionFactory())) {
  535. // transacted session created by this template -> commit
  536. session.commit();
  537. }
  538. }
  539. protected void doSend(MessageProducer producer, Message message) throws JMSException {
  540. if (isExplicitQosEnabled()) {
  541. producer.send(message, getDeliveryMode(), getPriority(), getTimeToLive());
  542. }
  543. else {
  544. producer.send(message);
  545. }
  546. }
  547. public void convertAndSend(Object message) throws JmsException {
  548. if (getDefaultDestination() == null) {
  549. throw new IllegalStateException("No defaultDestination specified. Check configuration of JmsTemplate.");
  550. }
  551. convertAndSend(getDefaultDestination(), message);
  552. }
  553. public void convertAndSend(Destination destination, final Object message) throws JmsException {
  554. if (getMessageConverter() == null) {
  555. throw new IllegalStateException("No MessageConverter registered. Check configuration of JmsTemplate.");
  556. }
  557. send(destination, new MessageCreator() {
  558. public Message createMessage(Session session) throws JMSException {
  559. return getMessageConverter().toMessage(message, session);
  560. }
  561. });
  562. }
  563. public void convertAndSend(String destinationName, final Object message) throws JmsException {
  564. if (getMessageConverter() == null) {
  565. throw new IllegalStateException("No MessageConverter registered. Check configuration of JmsTemplate.");
  566. }
  567. send(destinationName, new MessageCreator() {
  568. public Message createMessage(Session session) throws JMSException {
  569. return getMessageConverter().toMessage(message, session);
  570. }
  571. });
  572. }
  573. public void convertAndSend(Object message, MessagePostProcessor postProcessor) throws JmsException {
  574. if (getDefaultDestination() == null) {
  575. throw new IllegalStateException("No defaultDestination specified. Check configuration of JmsTemplate.");
  576. }
  577. convertAndSend(getDefaultDestination(), message, postProcessor);
  578. }
  579. public void convertAndSend(Destination destination, final Object message,
  580.                            final MessagePostProcessor postProcessor) throws JmsException {
  581. if (getMessageConverter() == null) {
  582. throw new IllegalStateException("No MessageConverter registered. Check configuration of JmsTemplate.");
  583. }
  584. send(destination, new MessageCreator() {
  585. public Message createMessage(Session session) throws JMSException {
  586. Message m = getMessageConverter().toMessage(message, session);
  587. return postProcessor.postProcessMessage(m);
  588. }
  589. });
  590. }
  591. public void convertAndSend(String destinationName, final Object message, final MessagePostProcessor postProcessor)
  592.     throws JmsException {
  593. if (getMessageConverter() == null) {
  594. throw new IllegalStateException("No MessageConverter registered. Check configuration of JmsTemplate.");
  595. }
  596. send(destinationName, new MessageCreator() {
  597. public Message createMessage(Session session) throws JMSException {
  598. Message m = getMessageConverter().toMessage(message, session);
  599. return postProcessor.postProcessMessage(m);
  600. }
  601. });
  602. }
  603. public Message receive() throws JmsException {
  604. if (getDefaultDestination() == null) {
  605. throw new IllegalStateException("No defaultDestination specified. Check configuration of JmsTemplate.");
  606. }
  607. return receive(getDefaultDestination());
  608. }
  609. public Message receive(final Destination destination) throws JmsException {
  610. return (Message) execute(new SessionCallback() {
  611. public Object doInJms(Session session) throws JMSException {
  612. return doReceive(session, destination);
  613. }
  614. }, true);
  615. }
  616. public Message receive(final String destinationName) throws JmsException {
  617. return (Message) execute(new SessionCallback() {
  618. public Object doInJms(Session session) throws JMSException {
  619. Destination destination = resolveDestinationName(session, destinationName);
  620. return doReceive(session, destination);
  621. }
  622. }, true);
  623. }
  624. protected Message doReceive(Session session, Destination destination) throws JMSException {
  625. MessageConsumer consumer = createConsumer(session, destination);
  626. try {
  627. // use transaction timeout if available
  628. long timeout = getReceiveTimeout();
  629. ConnectionHolder conHolder =
  630. (ConnectionHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
  631. if (conHolder != null && conHolder.hasTimeout()) {
  632. timeout = conHolder.getTimeToLiveInMillis();
  633. }
  634. Message message = (timeout >= 0) ?
  635. consumer.receive(timeout) : consumer.receive();
  636. if (session.getTransacted()) {
  637. if (conHolder == null) {
  638. // transacted session created by this template -> commit
  639. session.commit();
  640. }
  641. }
  642. else if (message != null && isClientAcknowledge(session)) {
  643. message.acknowledge();
  644. }
  645. return message;
  646. }
  647. finally {
  648. JmsUtils.closeMessageConsumer(consumer);
  649. }
  650. }
  651. protected boolean isClientAcknowledge(Session session) throws JMSException {
  652. return (session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
  653. }
  654. public Object receiveAndConvert() throws JmsException {
  655. if (getMessageConverter() == null) {
  656. throw new IllegalStateException("No MessageConverter registered. Check configuration of JmsTemplate.");
  657. }
  658. return doConvertFromMessage(receive());
  659. }
  660. public Object receiveAndConvert(Destination destination) throws JmsException {
  661. if (getMessageConverter() == null) {
  662. throw new IllegalStateException("No MessageConverter registered. Check configuration of JmsTemplate.");
  663. }
  664. return doConvertFromMessage(receive(destination));
  665. }
  666. public Object receiveAndConvert(String destinationName) throws JmsException {
  667. if (getMessageConverter() == null) {
  668. throw new IllegalStateException("No MessageConverter registered. Check configuration of JmsTemplate.");
  669. }
  670. return doConvertFromMessage(receive(destinationName));
  671. }
  672. protected Object doConvertFromMessage(Message message) {
  673. try {
  674. return getMessageConverter().fromMessage(message);
  675. }
  676. catch (JMSException ex) {
  677. throw convertJmsAccessException(ex);
  678. }
  679. }
  680. }