001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.transport.amqp.message; 018 019import static org.apache.activemq.transport.amqp.message.AmqpMessageSupport.JMS_AMQP_CONTENT_ENCODING; 020import static org.apache.activemq.transport.amqp.message.AmqpMessageSupport.JMS_AMQP_CONTENT_TYPE; 021import static org.apache.activemq.transport.amqp.message.AmqpMessageSupport.JMS_AMQP_FIRST_ACQUIRER; 022import static org.apache.activemq.transport.amqp.message.AmqpMessageSupport.JMS_AMQP_FOOTER_PREFIX; 023import static org.apache.activemq.transport.amqp.message.AmqpMessageSupport.JMS_AMQP_HEADER; 024import static org.apache.activemq.transport.amqp.message.AmqpMessageSupport.JMS_AMQP_MESSAGE_ANNOTATION_PREFIX; 025import static org.apache.activemq.transport.amqp.message.AmqpMessageSupport.JMS_AMQP_PROPERTIES; 026import static org.apache.activemq.transport.amqp.message.AmqpMessageSupport.JMS_AMQP_REPLYTO_GROUP_ID; 027 028import java.nio.charset.StandardCharsets; 029import java.util.Map; 030import java.util.Set; 031 032import javax.jms.JMSException; 033import javax.jms.Message; 034 035import org.apache.activemq.ScheduledMessage; 036import org.apache.activemq.command.ActiveMQDestination; 037import org.apache.activemq.command.ActiveMQMessage; 038import org.apache.activemq.transport.amqp.AmqpProtocolException; 039import org.apache.qpid.proton.amqp.Binary; 040import org.apache.qpid.proton.amqp.Decimal128; 041import org.apache.qpid.proton.amqp.Decimal32; 042import org.apache.qpid.proton.amqp.Decimal64; 043import org.apache.qpid.proton.amqp.Symbol; 044import org.apache.qpid.proton.amqp.UnsignedByte; 045import org.apache.qpid.proton.amqp.UnsignedInteger; 046import org.apache.qpid.proton.amqp.UnsignedLong; 047import org.apache.qpid.proton.amqp.UnsignedShort; 048import org.apache.qpid.proton.amqp.messaging.ApplicationProperties; 049import org.apache.qpid.proton.amqp.messaging.Footer; 050import org.apache.qpid.proton.amqp.messaging.Header; 051import org.apache.qpid.proton.amqp.messaging.MessageAnnotations; 052import org.apache.qpid.proton.amqp.messaging.Properties; 053 054public abstract class InboundTransformer { 055 056 public static final String TRANSFORMER_NATIVE = "native"; 057 public static final String TRANSFORMER_RAW = "raw"; 058 public static final String TRANSFORMER_JMS = "jms"; 059 060 public abstract String getTransformerName(); 061 062 public abstract InboundTransformer getFallbackTransformer(); 063 064 public final ActiveMQMessage transform(EncodedMessage amqpMessage) throws Exception { 065 InboundTransformer transformer = this; 066 ActiveMQMessage message = null; 067 068 while (transformer != null) { 069 try { 070 message = transformer.doTransform(amqpMessage); 071 break; 072 } catch (Exception e) { 073 transformer = transformer.getFallbackTransformer(); 074 } 075 } 076 077 if (message == null) { 078 throw new AmqpProtocolException("Failed to transform incoming delivery, skipping.", false); 079 } 080 081 return message; 082 } 083 084 protected abstract ActiveMQMessage doTransform(EncodedMessage amqpMessage) throws Exception; 085 086 @SuppressWarnings("unchecked") 087 protected void populateMessage(ActiveMQMessage jms, org.apache.qpid.proton.message.Message amqp) throws Exception { 088 Header header = amqp.getHeader(); 089 if (header != null) { 090 jms.setBooleanProperty(JMS_AMQP_HEADER, true); 091 092 if (header.getDurable() != null) { 093 jms.setPersistent(header.getDurable().booleanValue()); 094 } else { 095 jms.setPersistent(false); 096 } 097 098 if (header.getPriority() != null) { 099 jms.setJMSPriority(header.getPriority().intValue()); 100 } else { 101 jms.setPriority((byte) Message.DEFAULT_PRIORITY); 102 } 103 104 if (header.getFirstAcquirer() != null) { 105 jms.setBooleanProperty(JMS_AMQP_FIRST_ACQUIRER, header.getFirstAcquirer()); 106 } 107 108 if (header.getDeliveryCount() != null) { 109 jms.setRedeliveryCounter(header.getDeliveryCount().intValue()); 110 } 111 } else { 112 jms.setPriority((byte) Message.DEFAULT_PRIORITY); 113 jms.setPersistent(false); 114 } 115 116 final MessageAnnotations ma = amqp.getMessageAnnotations(); 117 if (ma != null) { 118 for (Map.Entry<?, ?> entry : ma.getValue().entrySet()) { 119 String key = entry.getKey().toString(); 120 if ("x-opt-delivery-time".equals(key) && entry.getValue() != null) { 121 long deliveryTime = ((Number) entry.getValue()).longValue(); 122 long delay = deliveryTime - System.currentTimeMillis(); 123 if (delay > 0) { 124 jms.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, delay); 125 } 126 } else if ("x-opt-delivery-delay".equals(key) && entry.getValue() != null) { 127 long delay = ((Number) entry.getValue()).longValue(); 128 if (delay > 0) { 129 jms.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, delay); 130 } 131 } else if ("x-opt-delivery-repeat".equals(key) && entry.getValue() != null) { 132 int repeat = ((Number) entry.getValue()).intValue(); 133 if (repeat > 0) { 134 jms.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, repeat); 135 } 136 } else if ("x-opt-delivery-period".equals(key) && entry.getValue() != null) { 137 long period = ((Number) entry.getValue()).longValue(); 138 if (period > 0) { 139 jms.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, period); 140 } 141 } else if ("x-opt-delivery-cron".equals(key) && entry.getValue() != null) { 142 String cronEntry = (String) entry.getValue(); 143 if (cronEntry != null) { 144 jms.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, cronEntry); 145 } 146 } 147 148 setProperty(jms, JMS_AMQP_MESSAGE_ANNOTATION_PREFIX + key, entry.getValue()); 149 } 150 } 151 152 final ApplicationProperties ap = amqp.getApplicationProperties(); 153 if (ap != null) { 154 for (Map.Entry<String, Object> entry : ((Map<String, Object>) ap.getValue()).entrySet()) { 155 setProperty(jms, entry.getKey(), entry.getValue()); 156 } 157 } 158 159 final Properties properties = amqp.getProperties(); 160 if (properties != null) { 161 jms.setBooleanProperty(JMS_AMQP_PROPERTIES, true); 162 if (properties.getMessageId() != null) { 163 jms.setJMSMessageID(AMQPMessageIdHelper.INSTANCE.toBaseMessageIdString(properties.getMessageId())); 164 } 165 Binary userId = properties.getUserId(); 166 if (userId != null) { 167 jms.setUserID(new String(userId.getArray(), userId.getArrayOffset(), userId.getLength(), StandardCharsets.UTF_8)); 168 } 169 if (properties.getTo() != null) { 170 jms.setDestination((ActiveMQDestination.createDestination(properties.getTo(), ActiveMQDestination.QUEUE_TYPE))); 171 } 172 if (properties.getSubject() != null) { 173 jms.setType(properties.getSubject()); 174 } 175 if (properties.getReplyTo() != null) { 176 jms.setReplyTo((ActiveMQDestination.createDestination(properties.getReplyTo(), ActiveMQDestination.QUEUE_TYPE))); 177 } 178 if (properties.getCorrelationId() != null) { 179 jms.setCorrelationId(AMQPMessageIdHelper.INSTANCE.toBaseMessageIdString(properties.getCorrelationId())); 180 } 181 if (properties.getContentType() != null) { 182 jms.setStringProperty(JMS_AMQP_CONTENT_TYPE, properties.getContentType().toString()); 183 } 184 if (properties.getContentEncoding() != null) { 185 jms.setStringProperty(JMS_AMQP_CONTENT_ENCODING, properties.getContentEncoding().toString()); 186 } 187 if (properties.getCreationTime() != null) { 188 jms.setTimestamp(properties.getCreationTime().getTime()); 189 } 190 if (properties.getGroupId() != null) { 191 jms.setGroupID(properties.getGroupId()); 192 } 193 if (properties.getGroupSequence() != null) { 194 jms.setGroupSequence(properties.getGroupSequence().intValue()); 195 } 196 if (properties.getReplyToGroupId() != null) { 197 jms.setStringProperty(JMS_AMQP_REPLYTO_GROUP_ID, properties.getReplyToGroupId()); 198 } 199 if (properties.getAbsoluteExpiryTime() != null) { 200 jms.setExpiration(properties.getAbsoluteExpiryTime().getTime()); 201 } 202 } 203 204 // If the jms expiration has not yet been set... 205 if (header != null && jms.getJMSExpiration() == 0) { 206 // Then lets try to set it based on the message ttl. 207 long ttl = Message.DEFAULT_TIME_TO_LIVE; 208 if (header.getTtl() != null) { 209 ttl = header.getTtl().longValue(); 210 } 211 212 if (ttl != javax.jms.Message.DEFAULT_TIME_TO_LIVE) { 213 jms.setExpiration(System.currentTimeMillis() + ttl); 214 } 215 } 216 217 final Footer fp = amqp.getFooter(); 218 if (fp != null) { 219 for (Map.Entry<Object, Object> entry : (Set<Map.Entry<Object, Object>>) fp.getValue().entrySet()) { 220 String key = entry.getKey().toString(); 221 setProperty(jms, JMS_AMQP_FOOTER_PREFIX + key, entry.getValue()); 222 } 223 } 224 } 225 226 private void setProperty(Message msg, String key, Object value) throws JMSException { 227 if (value instanceof UnsignedLong) { 228 long v = ((UnsignedLong) value).longValue(); 229 msg.setLongProperty(key, v); 230 } else if (value instanceof UnsignedInteger) { 231 long v = ((UnsignedInteger) value).longValue(); 232 if (Integer.MIN_VALUE <= v && v <= Integer.MAX_VALUE) { 233 msg.setIntProperty(key, (int) v); 234 } else { 235 msg.setLongProperty(key, v); 236 } 237 } else if (value instanceof UnsignedShort) { 238 int v = ((UnsignedShort) value).intValue(); 239 if (Short.MIN_VALUE <= v && v <= Short.MAX_VALUE) { 240 msg.setShortProperty(key, (short) v); 241 } else { 242 msg.setIntProperty(key, v); 243 } 244 } else if (value instanceof UnsignedByte) { 245 short v = ((UnsignedByte) value).shortValue(); 246 if (Byte.MIN_VALUE <= v && v <= Byte.MAX_VALUE) { 247 msg.setByteProperty(key, (byte) v); 248 } else { 249 msg.setShortProperty(key, v); 250 } 251 } else if (value instanceof Symbol) { 252 msg.setStringProperty(key, value.toString()); 253 } else if (value instanceof Decimal128) { 254 msg.setDoubleProperty(key, ((Decimal128) value).doubleValue()); 255 } else if (value instanceof Decimal64) { 256 msg.setDoubleProperty(key, ((Decimal64) value).doubleValue()); 257 } else if (value instanceof Decimal32) { 258 msg.setFloatProperty(key, ((Decimal32) value).floatValue()); 259 } else if (value instanceof Binary) { 260 msg.setStringProperty(key, value.toString()); 261 } else { 262 msg.setObjectProperty(key, value); 263 } 264 } 265}