001/*
002 * Copyright 2002-2018 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.support.converter;
018
019import java.util.Map;
020
021import javax.jms.JMSException;
022import javax.jms.Session;
023
024import org.springframework.beans.factory.InitializingBean;
025import org.springframework.jms.support.JmsHeaderMapper;
026import org.springframework.jms.support.SimpleJmsHeaderMapper;
027import org.springframework.lang.Nullable;
028import org.springframework.messaging.Message;
029import org.springframework.messaging.MessageHeaders;
030import org.springframework.messaging.core.AbstractMessagingTemplate;
031import org.springframework.messaging.support.MessageBuilder;
032import org.springframework.util.Assert;
033
034/**
035 * Convert a {@link Message} from the messaging abstraction to and from a
036 * {@link javax.jms.Message} using an underlying {@link MessageConverter}
037 * for the payload and a {@link org.springframework.jms.support.JmsHeaderMapper}
038 * to map the JMS headers to and from standard message headers.
039 *
040 * @author Stephane Nicoll
041 * @since 4.1
042 */
043public class MessagingMessageConverter implements MessageConverter, InitializingBean {
044
045        private MessageConverter payloadConverter;
046
047        private JmsHeaderMapper headerMapper;
048
049
050        /**
051         * Create an instance with a default payload converter.
052         * @see org.springframework.jms.support.converter.SimpleMessageConverter
053         * @see org.springframework.jms.support.SimpleJmsHeaderMapper
054         */
055        public MessagingMessageConverter() {
056                this(new SimpleMessageConverter(), new SimpleJmsHeaderMapper());
057        }
058
059        /**
060         * Create an instance with the specific payload converter.
061         * @param payloadConverter the payload converter to use
062         * @since 4.3.12
063         */
064        public MessagingMessageConverter(MessageConverter payloadConverter) {
065                this(payloadConverter, new SimpleJmsHeaderMapper());
066        }
067
068        /**
069         * Create an instance with the specified payload converter and
070         * header mapper.
071         */
072        public MessagingMessageConverter(MessageConverter payloadConverter, JmsHeaderMapper headerMapper) {
073                Assert.notNull(payloadConverter, "PayloadConverter must not be null");
074                Assert.notNull(headerMapper, "HeaderMapper must not be null");
075                this.payloadConverter = payloadConverter;
076                this.headerMapper = headerMapper;
077        }
078
079
080        /**
081         * Set the {@link MessageConverter} to use to convert the payload.
082         */
083        public void setPayloadConverter(MessageConverter payloadConverter) {
084                this.payloadConverter = payloadConverter;
085        }
086
087        /**
088         * Set the {@link JmsHeaderMapper} to use to map JMS headers to and from
089         * standard message headers.
090         */
091        public void setHeaderMapper(JmsHeaderMapper headerMapper) {
092                this.headerMapper = headerMapper;
093        }
094
095        @Override
096        public void afterPropertiesSet() {
097                Assert.notNull(this.payloadConverter, "Property 'payloadConverter' is required");
098                Assert.notNull(this.headerMapper, "Property 'headerMapper' is required");
099        }
100
101
102        @Override
103        public javax.jms.Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
104                if (!(object instanceof Message)) {
105                        throw new IllegalArgumentException("Could not convert [" + object + "] - only [" +
106                                        Message.class.getName() + "] is handled by this converter");
107                }
108                Message<?> input = (Message<?>) object;
109                MessageHeaders headers = input.getHeaders();
110                Object conversionHint = headers.get(AbstractMessagingTemplate.CONVERSION_HINT_HEADER);
111                javax.jms.Message reply = createMessageForPayload(input.getPayload(), session, conversionHint);
112                this.headerMapper.fromHeaders(headers, reply);
113                return reply;
114        }
115
116        @SuppressWarnings("unchecked")
117        @Override
118        public Object fromMessage(javax.jms.Message message) throws JMSException, MessageConversionException {
119                Map<String, Object> mappedHeaders = extractHeaders(message);
120                Object convertedObject = extractPayload(message);
121                MessageBuilder<Object> builder = (convertedObject instanceof org.springframework.messaging.Message ?
122                                MessageBuilder.fromMessage((org.springframework.messaging.Message<Object>) convertedObject) :
123                                MessageBuilder.withPayload(convertedObject));
124                return builder.copyHeadersIfAbsent(mappedHeaders).build();
125        }
126
127        /**
128         * Extract the payload of the specified {@link javax.jms.Message}.
129         */
130        protected Object extractPayload(javax.jms.Message message) throws JMSException {
131                return this.payloadConverter.fromMessage(message);
132        }
133
134        /**
135         * Create a JMS message for the specified payload and conversionHint.
136         * The conversion hint is an extra object passed to the {@link MessageConverter},
137         * e.g. the associated {@code MethodParameter} (may be {@code null}}.
138         * @since 4.3
139         * @see MessageConverter#toMessage(Object, Session)
140         */
141        protected javax.jms.Message createMessageForPayload(
142                        Object payload, Session session, @Nullable Object conversionHint) throws JMSException {
143
144                return this.payloadConverter.toMessage(payload, session);
145        }
146
147        protected final MessageHeaders extractHeaders(javax.jms.Message message) {
148                return this.headerMapper.toHeaders(message);
149        }
150
151}