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;
018
019import java.util.Arrays;
020import java.util.Enumeration;
021import java.util.HashMap;
022import java.util.HashSet;
023import java.util.Map;
024import java.util.Set;
025import javax.jms.Destination;
026import javax.jms.JMSException;
027import javax.jms.Message;
028
029import org.springframework.messaging.MessageHeaders;
030import org.springframework.messaging.support.AbstractHeaderMapper;
031import org.springframework.util.StringUtils;
032
033/**
034 * Simple implementation of {@link JmsHeaderMapper}.
035 *
036 * <p>This implementation copies JMS API headers (e.g. JMSReplyTo) to and from
037 * {@link org.springframework.messaging.Message Messages}. Any user-defined
038 * properties will also be copied from a JMS Message to a Message, and any
039 * other headers on a Message (beyond the JMS API headers) will likewise
040 * be copied to a JMS Message. Those other headers will be copied to the
041 * general properties of a JMS Message whereas the JMS API headers are passed
042 * to the appropriate setter methods (e.g. setJMSReplyTo).
043 *
044 * <p>Constants for the JMS API headers are defined in {@link JmsHeaders}.
045 * Note that most of the JMS headers are read-only: the JMSDestination,
046 * JMSDeliveryMode, JMSExpiration, JMSMessageID, JMSPriority, JMSRedelivered
047 * and JMSTimestamp flags are only copied <em>from</em> a JMS Message. Those
048 * values will <em>not</em> be passed along from a Message to an outbound
049 * JMS Message.
050 *
051 * @author Mark Fisher
052 * @author Gary Russell
053 * @author Stephane Nicoll
054 * @since 4.1
055 */
056public class SimpleJmsHeaderMapper extends AbstractHeaderMapper<Message> implements JmsHeaderMapper {
057
058        private static final Set<Class<?>> SUPPORTED_PROPERTY_TYPES = new HashSet<Class<?>>(Arrays.asList(new Class<?>[] {
059                        Boolean.class, Byte.class, Double.class, Float.class, Integer.class, Long.class, Short.class, String.class}));
060
061
062        @Override
063        public void fromHeaders(MessageHeaders headers, javax.jms.Message jmsMessage) {
064                try {
065                        Object jmsCorrelationId = headers.get(JmsHeaders.CORRELATION_ID);
066                        if (jmsCorrelationId instanceof Number) {
067                                jmsCorrelationId = jmsCorrelationId.toString();
068                        }
069                        if (jmsCorrelationId instanceof String) {
070                                try {
071                                        jmsMessage.setJMSCorrelationID((String) jmsCorrelationId);
072                                }
073                                catch (Exception ex) {
074                                        logger.info("Failed to set JMSCorrelationID - skipping", ex);
075                                }
076                        }
077                        Destination jmsReplyTo = getHeaderIfAvailable(headers, JmsHeaders.REPLY_TO, Destination.class);
078                        if (jmsReplyTo != null) {
079                                try {
080                                        jmsMessage.setJMSReplyTo(jmsReplyTo);
081                                }
082                                catch (Exception ex) {
083                                        logger.info("Failed to set JMSReplyTo - skipping", ex);
084                                }
085                        }
086                        String jmsType = getHeaderIfAvailable(headers, JmsHeaders.TYPE, String.class);
087                        if (jmsType != null) {
088                                try {
089                                        jmsMessage.setJMSType(jmsType);
090                                }
091                                catch (Exception ex) {
092                                        logger.info("Failed to set JMSType - skipping", ex);
093                                }
094                        }
095                        Set<String> headerNames = headers.keySet();
096                        for (String headerName : headerNames) {
097                                if (StringUtils.hasText(headerName) && !headerName.startsWith(JmsHeaders.PREFIX)) {
098                                        Object value = headers.get(headerName);
099                                        if (value != null && SUPPORTED_PROPERTY_TYPES.contains(value.getClass())) {
100                                                try {
101                                                        String propertyName = this.fromHeaderName(headerName);
102                                                        jmsMessage.setObjectProperty(propertyName, value);
103                                                }
104                                                catch (Exception ex) {
105                                                        if (headerName.startsWith("JMSX")) {
106                                                                if (logger.isTraceEnabled()) {
107                                                                        logger.trace("Skipping reserved header '" + headerName +
108                                                                                        "' since it cannot be set by client");
109                                                                }
110                                                        }
111                                                        else if (logger.isWarnEnabled()) {
112                                                                logger.warn("Failed to map message header '" + headerName + "' to JMS property", ex);
113                                                        }
114                                                }
115                                        }
116                                }
117                        }
118                }
119                catch (Exception ex) {
120                        if (logger.isWarnEnabled()) {
121                                logger.warn("Error occurred while mapping from MessageHeaders to JMS properties", ex);
122                        }
123                }
124        }
125
126        @Override
127        public MessageHeaders toHeaders(javax.jms.Message jmsMessage) {
128                Map<String, Object> headers = new HashMap<String, Object>();
129                try {
130                        try {
131                                String correlationId = jmsMessage.getJMSCorrelationID();
132                                if (correlationId != null) {
133                                        headers.put(JmsHeaders.CORRELATION_ID, correlationId);
134                                }
135                        }
136                        catch (Exception ex) {
137                                logger.info("Failed to read JMSCorrelationID property - skipping", ex);
138                        }
139                        try {
140                                Destination destination = jmsMessage.getJMSDestination();
141                                if (destination != null) {
142                                        headers.put(JmsHeaders.DESTINATION, destination);
143                                }
144                        }
145                        catch (Exception ex) {
146                                logger.info("Failed to read JMSDestination property - skipping", ex);
147                        }
148                        try {
149                                int deliveryMode = jmsMessage.getJMSDeliveryMode();
150                                headers.put(JmsHeaders.DELIVERY_MODE, deliveryMode);
151                        }
152                        catch (Exception ex) {
153                                logger.info("Failed to read JMSDeliveryMode property - skipping", ex);
154                        }
155                        try {
156                                long expiration = jmsMessage.getJMSExpiration();
157                                headers.put(JmsHeaders.EXPIRATION, expiration);
158                        }
159                        catch (Exception ex) {
160                                logger.info("Failed to read JMSExpiration property - skipping", ex);
161                        }
162                        try {
163                                String messageId = jmsMessage.getJMSMessageID();
164                                if (messageId != null) {
165                                        headers.put(JmsHeaders.MESSAGE_ID, messageId);
166                                }
167                        }
168                        catch (Exception ex) {
169                                logger.info("Failed to read JMSMessageID property - skipping", ex);
170                        }
171                        try {
172                                headers.put(JmsHeaders.PRIORITY, jmsMessage.getJMSPriority());
173                        }
174                        catch (Exception ex) {
175                                logger.info("Failed to read JMSPriority property - skipping", ex);
176                        }
177                        try {
178                                Destination replyTo = jmsMessage.getJMSReplyTo();
179                                if (replyTo != null) {
180                                        headers.put(JmsHeaders.REPLY_TO, replyTo);
181                                }
182                        }
183                        catch (Exception ex) {
184                                logger.info("Failed to read JMSReplyTo property - skipping", ex);
185                        }
186                        try {
187                                headers.put(JmsHeaders.REDELIVERED, jmsMessage.getJMSRedelivered());
188                        }
189                        catch (Exception ex) {
190                                logger.info("Failed to read JMSRedelivered property - skipping", ex);
191                        }
192                        try {
193                                String type = jmsMessage.getJMSType();
194                                if (type != null) {
195                                        headers.put(JmsHeaders.TYPE, type);
196                                }
197                        }
198                        catch (Exception ex) {
199                                logger.info("Failed to read JMSType property - skipping", ex);
200                        }
201                        try {
202                                headers.put(JmsHeaders.TIMESTAMP, jmsMessage.getJMSTimestamp());
203                        }
204                        catch (Exception ex) {
205                                logger.info("Failed to read JMSTimestamp property - skipping", ex);
206                        }
207
208                        Enumeration<?> jmsPropertyNames = jmsMessage.getPropertyNames();
209                        if (jmsPropertyNames != null) {
210                                while (jmsPropertyNames.hasMoreElements()) {
211                                        String propertyName = jmsPropertyNames.nextElement().toString();
212                                        try {
213                                                String headerName = this.toHeaderName(propertyName);
214                                                headers.put(headerName, jmsMessage.getObjectProperty(propertyName));
215                                        }
216                                        catch (Exception ex) {
217                                                if (logger.isWarnEnabled()) {
218                                                        logger.warn("Error occurred while mapping JMS property '" + propertyName +
219                                                                        "' to Message header", ex);
220                                                }
221                                        }
222                                }
223                        }
224                }
225                catch (JMSException ex) {
226                        if (logger.isWarnEnabled()) {
227                                logger.warn("Error occurred while mapping from JMS properties to MessageHeaders", ex);
228                        }
229                }
230                return new MessageHeaders(headers);
231        }
232
233        /**
234         * Add the outbound prefix if necessary.
235         * <p>Convert {@link MessageHeaders#CONTENT_TYPE} to {@code content_type} for JMS compliance.
236         * @see #CONTENT_TYPE_PROPERTY
237         */
238        @Override
239        protected String fromHeaderName(String headerName) {
240                if (MessageHeaders.CONTENT_TYPE.equals(headerName)) {
241                        return CONTENT_TYPE_PROPERTY;
242                }
243                return super.fromHeaderName(headerName);
244        }
245
246        /**
247         * Add the inbound prefix if necessary.
248         * <p>Convert the JMS-compliant {@code content_type} to {@link MessageHeaders#CONTENT_TYPE}.
249         * @see #CONTENT_TYPE_PROPERTY
250         */
251        @Override
252        protected String toHeaderName(String propertyName) {
253                if (CONTENT_TYPE_PROPERTY.equals(propertyName)) {
254                        return MessageHeaders.CONTENT_TYPE;
255                }
256                return super.toHeaderName(propertyName);
257        }
258
259}