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}