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