001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jms.core;
018
019import java.util.Map;
020import javax.jms.ConnectionFactory;
021import javax.jms.Destination;
022import javax.jms.JMSException;
023import javax.jms.Session;
024
025import org.springframework.beans.factory.InitializingBean;
026import org.springframework.jms.InvalidDestinationException;
027import org.springframework.jms.JmsException;
028import org.springframework.jms.support.converter.MessageConverter;
029import org.springframework.jms.support.converter.MessagingMessageConverter;
030import org.springframework.jms.support.converter.SimpleMessageConverter;
031import org.springframework.messaging.Message;
032import org.springframework.messaging.MessagingException;
033import org.springframework.messaging.converter.MessageConversionException;
034import org.springframework.messaging.core.AbstractMessagingTemplate;
035import org.springframework.messaging.core.DestinationResolutionException;
036import org.springframework.messaging.core.MessagePostProcessor;
037import org.springframework.util.Assert;
038
039/**
040 * An implementation of {@link JmsMessageOperations}.
041 *
042 * @author Stephane Nicoll
043 * @author Juergen Hoeller
044 * @since 4.1
045 */
046public class JmsMessagingTemplate extends AbstractMessagingTemplate<Destination>
047                implements JmsMessageOperations, InitializingBean {
048
049        private JmsTemplate jmsTemplate;
050
051        private MessageConverter jmsMessageConverter = new MessagingMessageConverter();
052
053        private boolean converterSet;
054
055        private String defaultDestinationName;
056
057
058        /**
059         * Constructor for use with bean properties.
060         * Requires {@link #setConnectionFactory} or {@link #setJmsTemplate} to be called.
061         */
062        public JmsMessagingTemplate() {
063        }
064
065        /**
066         * Create a {@code JmsMessagingTemplate} instance with the JMS {@link ConnectionFactory}
067         * to use, implicitly building a {@link JmsTemplate} based on it.
068         * @since 4.1.2
069         */
070        public JmsMessagingTemplate(ConnectionFactory connectionFactory) {
071                this.jmsTemplate = new JmsTemplate(connectionFactory);
072        }
073
074        /**
075         * Create a {@code JmsMessagingTemplate} instance with the {@link JmsTemplate} to use.
076         */
077        public JmsMessagingTemplate(JmsTemplate jmsTemplate) {
078                Assert.notNull(jmsTemplate, "JmsTemplate must not be null");
079                this.jmsTemplate = jmsTemplate;
080        }
081
082
083        /**
084         * Set the ConnectionFactory to use for the underlying {@link JmsTemplate}.
085         * @since 4.1.2
086         */
087        public void setConnectionFactory(ConnectionFactory connectionFactory) {
088                if (this.jmsTemplate != null) {
089                        this.jmsTemplate.setConnectionFactory(connectionFactory);
090                }
091                else {
092                        this.jmsTemplate = new JmsTemplate(connectionFactory);
093                }
094        }
095
096        /**
097         * Return the ConnectionFactory that the underlying {@link JmsTemplate} uses.
098         * @since 4.1.2
099         */
100        public ConnectionFactory getConnectionFactory() {
101                return (this.jmsTemplate != null ? this.jmsTemplate.getConnectionFactory() : null);
102        }
103
104        /**
105         * Set the {@link JmsTemplate} to use.
106         */
107        public void setJmsTemplate(JmsTemplate jmsTemplate) {
108                this.jmsTemplate = jmsTemplate;
109        }
110
111        /**
112         * Return the configured {@link JmsTemplate}.
113         */
114        public JmsTemplate getJmsTemplate() {
115                return this.jmsTemplate;
116        }
117
118        /**
119         * Set the {@link MessageConverter} to use to convert a {@link Message} from
120         * the messaging to and from a {@link javax.jms.Message}. By default, a
121         * {@link MessagingMessageConverter} is defined using a {@link SimpleMessageConverter}
122         * to convert the payload of the message.
123         * <p>Consider configuring a {@link MessagingMessageConverter} with a different
124         * {@link MessagingMessageConverter#setPayloadConverter(MessageConverter) payload converter}
125         * for more advanced scenarios.
126         * @see org.springframework.jms.support.converter.MessagingMessageConverter
127         */
128        public void setJmsMessageConverter(MessageConverter jmsMessageConverter) {
129                Assert.notNull(jmsMessageConverter, "MessageConverter must not be null");
130                this.jmsMessageConverter = jmsMessageConverter;
131                this.converterSet = true;
132        }
133
134        /**
135         * Return the {@link MessageConverter} to use to convert a {@link Message}
136         * from the messaging to and from a {@link javax.jms.Message}.
137         */
138        public MessageConverter getJmsMessageConverter() {
139                return this.jmsMessageConverter;
140        }
141
142        /**
143         * Configure the default destination name to use in send methods that don't have
144         * a destination argument. If a default destination is not configured, send methods
145         * without a destination argument will raise an exception if invoked.
146         * @see #setDefaultDestination(Object)
147         */
148        public void setDefaultDestinationName(String defaultDestinationName) {
149                this.defaultDestinationName = defaultDestinationName;
150        }
151
152        /**
153         * Return the configured default destination name.
154         */
155        public String getDefaultDestinationName() {
156                return this.defaultDestinationName;
157        }
158
159        @Override
160        public void afterPropertiesSet() {
161                Assert.notNull(this.jmsTemplate, "Property 'connectionFactory' or 'jmsTemplate' is required");
162                if (!this.converterSet && this.jmsTemplate.getMessageConverter() != null) {
163                        ((MessagingMessageConverter) this.jmsMessageConverter)
164                                        .setPayloadConverter(this.jmsTemplate.getMessageConverter());
165                }
166        }
167
168
169        @Override
170        public void send(Message<?> message) {
171                Destination defaultDestination = getDefaultDestination();
172                if (defaultDestination != null) {
173                        send(defaultDestination, message);
174                }
175                else {
176                        send(getRequiredDefaultDestinationName(), message);
177                }
178        }
179
180        @Override
181        public void convertAndSend(Object payload) throws MessagingException {
182                convertAndSend(payload, null);
183        }
184
185        @Override
186        public void convertAndSend(Object payload, MessagePostProcessor postProcessor) throws MessagingException {
187                Destination defaultDestination = getDefaultDestination();
188                if (defaultDestination != null) {
189                        convertAndSend(defaultDestination, payload, postProcessor);
190                }
191                else {
192                        convertAndSend(getRequiredDefaultDestinationName(), payload, postProcessor);
193                }
194        }
195
196        @Override
197        public void send(String destinationName, Message<?> message) throws MessagingException {
198                doSend(destinationName, message);
199        }
200
201        @Override
202        public void convertAndSend(String destinationName, Object payload) throws MessagingException {
203                convertAndSend(destinationName, payload, (Map<String, Object>) null);
204        }
205
206        @Override
207        public void convertAndSend(String destinationName, Object payload, Map<String, Object> headers)
208                        throws MessagingException {
209
210                convertAndSend(destinationName, payload, headers, null);
211        }
212
213        @Override
214        public void convertAndSend(String destinationName, Object payload, MessagePostProcessor postProcessor)
215                        throws MessagingException {
216
217                convertAndSend(destinationName, payload, null, postProcessor);
218        }
219
220        @Override
221        public void convertAndSend(String destinationName, Object payload, Map<String, Object> headers,
222                        MessagePostProcessor postProcessor) throws MessagingException {
223
224                Message<?> message = doConvert(payload, headers, postProcessor);
225                send(destinationName, message);
226        }
227
228        @Override
229        public Message<?> receive() {
230                Destination defaultDestination = getDefaultDestination();
231                if (defaultDestination != null) {
232                        return receive(defaultDestination);
233                }
234                else {
235                        return receive(getRequiredDefaultDestinationName());
236                }
237        }
238
239        @Override
240        public <T> T receiveAndConvert(Class<T> targetClass) {
241                Destination defaultDestination = getDefaultDestination();
242                if (defaultDestination != null) {
243                        return receiveAndConvert(defaultDestination, targetClass);
244                }
245                else {
246                        return receiveAndConvert(getRequiredDefaultDestinationName(), targetClass);
247                }
248        }
249
250        @Override
251        public Message<?> receive(String destinationName) throws MessagingException {
252                return doReceive(destinationName);
253        }
254
255        @Override
256        public <T> T receiveAndConvert(String destinationName, Class<T> targetClass) throws MessagingException {
257                Message<?> message = doReceive(destinationName);
258                if (message != null) {
259                        return doConvert(message, targetClass);
260                }
261                else {
262                        return null;
263                }
264        }
265
266        @Override
267        public Message<?> sendAndReceive(Message<?> requestMessage) {
268                Destination defaultDestination = getDefaultDestination();
269                if (defaultDestination != null) {
270                        return sendAndReceive(defaultDestination, requestMessage);
271                }
272                else {
273                        return sendAndReceive(getRequiredDefaultDestinationName(), requestMessage);
274                }
275        }
276
277        @Override
278        public Message<?> sendAndReceive(String destinationName, Message<?> requestMessage) throws MessagingException {
279                return doSendAndReceive(destinationName, requestMessage);
280        }
281
282        @Override
283        public <T> T convertSendAndReceive(String destinationName, Object request, Class<T> targetClass)
284                        throws MessagingException {
285
286                return convertSendAndReceive(destinationName, request, null, targetClass);
287        }
288
289        @Override
290        public <T> T convertSendAndReceive(Object request, Class<T> targetClass) {
291                return convertSendAndReceive(request, targetClass, null);
292        }
293
294        @Override
295        public <T> T convertSendAndReceive(String destinationName, Object request,
296                        Map<String, Object> headers, Class<T> targetClass) throws MessagingException {
297
298                return convertSendAndReceive(destinationName, request, headers, targetClass, null);
299        }
300
301        @Override
302        public <T> T convertSendAndReceive(Object request, Class<T> targetClass, MessagePostProcessor postProcessor) {
303                Destination defaultDestination = getDefaultDestination();
304                if (defaultDestination != null) {
305                        return convertSendAndReceive(defaultDestination, request, targetClass, postProcessor);
306                }
307                else {
308                        return convertSendAndReceive(getRequiredDefaultDestinationName(), request, targetClass, postProcessor);
309                }
310        }
311
312        @Override
313        public <T> T convertSendAndReceive(String destinationName, Object request, Class<T> targetClass,
314                        MessagePostProcessor requestPostProcessor) throws MessagingException {
315
316                return convertSendAndReceive(destinationName, request, null, targetClass, requestPostProcessor);
317        }
318
319        @SuppressWarnings("unchecked")
320        @Override
321        public <T> T convertSendAndReceive(String destinationName, Object request, Map<String, Object> headers,
322                        Class<T> targetClass, MessagePostProcessor postProcessor) {
323
324                Message<?> requestMessage = doConvert(request, headers, postProcessor);
325                Message<?> replyMessage = sendAndReceive(destinationName, requestMessage);
326                return (replyMessage != null ? (T) getMessageConverter().fromMessage(replyMessage, targetClass) : null);
327        }
328
329        @Override
330        protected void doSend(Destination destination, Message<?> message) {
331                try {
332                        this.jmsTemplate.send(destination, createMessageCreator(message));
333                }
334                catch (JmsException ex) {
335                        throw convertJmsException(ex);
336                }
337        }
338
339        protected void doSend(String destinationName, Message<?> message) {
340                try {
341                        this.jmsTemplate.send(destinationName, createMessageCreator(message));
342                }
343                catch (JmsException ex) {
344                        throw convertJmsException(ex);
345                }
346        }
347
348        @Override
349        protected Message<?> doReceive(Destination destination) {
350                try {
351                        javax.jms.Message jmsMessage = this.jmsTemplate.receive(destination);
352                        return convertJmsMessage(jmsMessage);
353                }
354                catch (JmsException ex) {
355                        throw convertJmsException(ex);
356                }
357        }
358
359        protected Message<?> doReceive(String destinationName) {
360                try {
361                        javax.jms.Message jmsMessage = this.jmsTemplate.receive(destinationName);
362                        return convertJmsMessage(jmsMessage);
363                }
364                catch (JmsException ex) {
365                        throw convertJmsException(ex);
366                }
367        }
368
369        @Override
370        protected Message<?> doSendAndReceive(Destination destination, Message<?> requestMessage) {
371                try {
372                        javax.jms.Message jmsMessage = this.jmsTemplate.sendAndReceive(
373                                        destination, createMessageCreator(requestMessage));
374                        return convertJmsMessage(jmsMessage);
375                }
376                catch (JmsException ex) {
377                        throw convertJmsException(ex);
378                }
379        }
380
381        protected Message<?> doSendAndReceive(String destinationName, Message<?> requestMessage) {
382                try {
383                        javax.jms.Message jmsMessage = this.jmsTemplate.sendAndReceive(
384                                        destinationName, createMessageCreator(requestMessage));
385                        return convertJmsMessage(jmsMessage);
386                }
387                catch (JmsException ex) {
388                        throw convertJmsException(ex);
389                }
390        }
391
392        private MessagingMessageCreator createMessageCreator(Message<?> message) {
393                return new MessagingMessageCreator(message, getJmsMessageConverter());
394        }
395
396        protected String getRequiredDefaultDestinationName() {
397                String name = getDefaultDestinationName();
398                if (name == null) {
399                        throw new IllegalStateException("No 'defaultDestination' or 'defaultDestinationName' specified. " +
400                                        "Check configuration of JmsMessagingTemplate.");
401                }
402                return name;
403        }
404
405        protected Message<?> convertJmsMessage(javax.jms.Message message) {
406                if (message == null) {
407                        return null;
408                }
409                try {
410                        return (Message<?>) getJmsMessageConverter().fromMessage(message);
411                }
412                catch (Exception ex) {
413                        throw new MessageConversionException("Could not convert '" + message + "'", ex);
414                }
415        }
416
417        protected MessagingException convertJmsException(JmsException ex) {
418                if (ex instanceof org.springframework.jms.support.destination.DestinationResolutionException ||
419                                ex instanceof InvalidDestinationException) {
420                        return new DestinationResolutionException(ex.getMessage(), ex);
421                }
422                if (ex instanceof org.springframework.jms.support.converter.MessageConversionException) {
423                        return new MessageConversionException(ex.getMessage(), ex);
424                }
425                // Fallback
426                return new MessagingException(ex.getMessage(), ex);
427        }
428
429
430        private static class MessagingMessageCreator implements MessageCreator {
431
432                private final Message<?> message;
433
434                private final MessageConverter messageConverter;
435
436                public MessagingMessageCreator(Message<?> message, MessageConverter messageConverter) {
437                        this.message = message;
438                        this.messageConverter = messageConverter;
439                }
440
441                @Override
442                public javax.jms.Message createMessage(Session session) throws JMSException {
443                        try {
444                                return this.messageConverter.toMessage(this.message, session);
445                        }
446                        catch (Exception ex) {
447                                throw new MessageConversionException("Could not convert '" + this.message + "'", ex);
448                        }
449                }
450        }
451
452}