| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.qpid.client.message; |
| |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.LinkedHashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.jms.JMSException; |
| import javax.jms.MessageFormatException; |
| |
| import org.apache.qpid.AMQPInvalidClassException; |
| import org.apache.qpid.client.util.JMSExceptionHelper; |
| import org.apache.qpid.framing.FieldTable; |
| |
| |
| public final class JMSHeaderAdapter |
| { |
| private static final Map<String,String> AMQP_TO_JMS_HEADER_NAME_MAPPINGS; |
| private static final Map<String,String> JMS_TO_AMQP_HEADER_NAME_MAPPINGS; |
| |
| |
| |
| static |
| { |
| String[][] mappings = { |
| { QpidMessageProperties.QPID_SUBJECT, QpidMessageProperties.QPID_SUBJECT_JMS_PROPERTY } |
| }; |
| |
| Map<String,String> amqpToJmsHeaderNameMappings = new HashMap<>(); |
| Map<String,String> jmsToAmqpHeaderNameMappings = new HashMap<>(); |
| |
| for(String[] mapping : mappings) |
| { |
| amqpToJmsHeaderNameMappings.put(mapping[0], mapping[1]); |
| jmsToAmqpHeaderNameMappings.put(mapping[1], mapping[0]); |
| } |
| |
| AMQP_TO_JMS_HEADER_NAME_MAPPINGS = Collections.unmodifiableMap(amqpToJmsHeaderNameMappings); |
| JMS_TO_AMQP_HEADER_NAME_MAPPINGS = Collections.unmodifiableMap(jmsToAmqpHeaderNameMappings); |
| } |
| |
| private static final boolean STRICT_JMS = Boolean.getBoolean("strict-jms"); |
| |
| |
| private final FieldTable _headers; |
| |
| public JMSHeaderAdapter(FieldTable headers) |
| { |
| _headers = headers; |
| } |
| |
| |
| private String mapJmsToAmqpName(String name) |
| { |
| return JMS_TO_AMQP_HEADER_NAME_MAPPINGS.containsKey(name) ? JMS_TO_AMQP_HEADER_NAME_MAPPINGS.get(name) : name; |
| } |
| |
| public boolean getBoolean(String name) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| Boolean b = _headers.getBoolean(amqpName); |
| |
| if (b == null) |
| { |
| if (_headers.containsKey(amqpName)) |
| { |
| Object str = _headers.getObject(amqpName); |
| |
| if (!(str instanceof String)) |
| { |
| throw new MessageFormatException("getBoolean can't use " + name + " item."); |
| } |
| else |
| { |
| return Boolean.valueOf((String) str); |
| } |
| } |
| else |
| { |
| b = Boolean.valueOf(null); |
| } |
| } |
| |
| return b; |
| } |
| |
| |
| public byte[] getBytes(String name) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| byte[] bs = _headers.getBytes(amqpName); |
| |
| if (bs == null) |
| { |
| throw new MessageFormatException("getBytes can't use " + name + " item."); |
| } |
| else |
| { |
| return bs; |
| } |
| } |
| |
| public byte getByte(String name) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| Byte b = _headers.getByte(amqpName); |
| if (b == null) |
| { |
| if (_headers.containsKey(amqpName)) |
| { |
| Object str = _headers.getObject(amqpName); |
| |
| if (!(str instanceof String)) |
| { |
| throw new MessageFormatException("getByte can't use " + name + " item."); |
| } |
| else |
| { |
| return Byte.valueOf((String) str); |
| } |
| } |
| else |
| { |
| b = Byte.valueOf(null); |
| } |
| } |
| |
| return b; |
| } |
| |
| public short getShort(String name) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| Short s = _headers.getShort(amqpName); |
| |
| if (s == null) |
| { |
| s = Short.valueOf(getByte(amqpName)); |
| } |
| |
| return s; |
| } |
| |
| public int getInteger(String name) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| Integer i = _headers.getInteger(amqpName); |
| |
| if (i == null) |
| { |
| i = Integer.valueOf(getShort(amqpName)); |
| } |
| |
| return i; |
| } |
| |
| public long getLong(String name) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| Long l = _headers.getLong(amqpName); |
| |
| if (l == null) |
| { |
| l = Long.valueOf(getInteger(amqpName)); |
| } |
| |
| return l; |
| } |
| |
| public float getFloat(String name) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| Float f = _headers.getFloat(amqpName); |
| |
| if (f == null) |
| { |
| if (_headers.containsKey(amqpName)) |
| { |
| Object str = _headers.getObject(amqpName); |
| |
| if (!(str instanceof String)) |
| { |
| throw new MessageFormatException("getFloat can't use " + name + " item."); |
| } |
| else |
| { |
| return Float.valueOf((String) str); |
| } |
| } |
| else |
| { |
| throw new NullPointerException("No such property: " + name); |
| } |
| |
| } |
| |
| return f; |
| } |
| |
| public double getDouble(String name) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| Double d = _headers.getDouble(amqpName); |
| |
| if (d == null) |
| { |
| d = Double.valueOf(getFloat(amqpName)); |
| } |
| |
| return d; |
| } |
| |
| public String getString(String name) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| String s = _headers.getString(amqpName); |
| |
| if (s == null) |
| { |
| if (_headers.containsKey(amqpName)) |
| { |
| Object o = _headers.getObject(amqpName); |
| if (o instanceof byte[]) |
| { |
| throw new MessageFormatException("getObject couldn't find " + name + " item."); |
| } |
| else |
| { |
| if (o == null) |
| { |
| return null; |
| } |
| else |
| { |
| s = String.valueOf(o); |
| } |
| } |
| } |
| } |
| |
| return s; |
| } |
| |
| public Object getObject(String name) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| return _headers.getObject(amqpName); |
| } |
| |
| public void setBoolean(String name, boolean b) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| _headers.setBoolean(amqpName, b); |
| } |
| |
| public void setByte(String name, byte b) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| _headers.setByte(amqpName, b); |
| } |
| |
| public void setShort(String name, short i) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| _headers.setShort(amqpName, i); |
| } |
| |
| public void setInteger(String name, int i) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| _headers.setInteger(amqpName, i); |
| } |
| |
| public void setLong(String name, long l) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| _headers.setLong(amqpName, l); |
| } |
| |
| public void setFloat(String name, float v) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| _headers.setFloat(amqpName, v); |
| } |
| |
| public void setDouble(String name, double v) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| _headers.setDouble(amqpName, v); |
| } |
| |
| public void setString(String name, String value) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| _headers.setString(amqpName, value); |
| } |
| |
| public void setObject(String name, Object object) throws JMSException |
| { |
| checkPropertyName(name); |
| String amqpName = mapJmsToAmqpName(name); |
| try |
| { |
| _headers.setObject(amqpName, object); |
| } |
| catch (AMQPInvalidClassException aice) |
| { |
| String msg = AMQPInvalidClassException.INVALID_OBJECT_MSG + (object == null ? "null" : object.getClass()); |
| throw JMSExceptionHelper.chainJMSException(new MessageFormatException(msg), aice); |
| } |
| } |
| |
| public Set<String> getPropertyNames() |
| { |
| Set<String> names = new LinkedHashSet<>(_headers.keys()); |
| for(Map.Entry<String,String> entry : AMQP_TO_JMS_HEADER_NAME_MAPPINGS.entrySet()) |
| { |
| if(names.contains(entry.getKey())) |
| { |
| names.add(entry.getValue()); |
| if(STRICT_JMS) |
| { |
| names.remove(entry.getKey()); |
| } |
| } |
| } |
| return names; |
| } |
| |
| public void clear() |
| { |
| _headers.clear(); |
| } |
| |
| public boolean propertyExists(String name) |
| { |
| checkPropertyName(name); |
| String propertyName = mapJmsToAmqpName(name); |
| return _headers.propertyExists(propertyName); |
| } |
| |
| public Object remove(String name) |
| { |
| checkPropertyName(name); |
| String propertyName = mapJmsToAmqpName(name); |
| return _headers.remove(propertyName); |
| } |
| |
| public boolean isEmpty() |
| { |
| return _headers.isEmpty(); |
| } |
| |
| protected void checkPropertyName(CharSequence propertyName) |
| { |
| if (propertyName == null) |
| { |
| throw new IllegalArgumentException("Property name must not be null"); |
| } |
| else if (propertyName.length() == 0) |
| { |
| throw new IllegalArgumentException("Property name must not be the empty string"); |
| } |
| |
| checkIdentifierFormat(propertyName); |
| } |
| |
| protected void checkIdentifierFormat(CharSequence propertyName) |
| { |
| // JMS requirements 3.5.1 Property Names |
| // Identifiers: |
| // - An identifier is an unlimited-length character sequence that must begin |
| // with a Java identifier start character; all following characters must be Java |
| // identifier part characters. An identifier start character is any character for |
| // which the method Character.isJavaIdentifierStart returns true. This includes |
| // '_' and '$'. An identifier part character is any character for which the |
| // method Character.isJavaIdentifierPart returns true. |
| // - Identifiers cannot be the names NULL, TRUE, or FALSE. |
| // Identifiers cannot be NOT, AND, OR, BETWEEN, LIKE, IN, IS, or |
| // ESCAPE. |
| // Identifiers are either header field references or property references. The |
| // type of a property value in a message selector corresponds to the type |
| // used to set the property. If a property that does not exist in a message is |
| // referenced, its value is NULL. The semantics of evaluating NULL values |
| // in a selector are described in Section 3.8.1.2, Null Values. |
| // The conversions that apply to the get methods for properties do not |
| // apply when a property is used in a message selector expression. For |
| // example, suppose you set a property as a string value, as in the |
| // following: |
| // myMessage.setStringProperty("NumberOfOrders", "2") |
| // The following expression in a message selector would evaluate to false, |
| // because a string cannot be used in an arithmetic expression: |
| // "NumberOfOrders > 1" |
| // Identifiers are case sensitive. |
| // Message header field references are restricted to JMSDeliveryMode, |
| // JMSPriority, JMSMessageID, JMSTimestamp, JMSCorrelationID, and |
| // JMSType. JMSMessageID, JMSCorrelationID, and JMSType values may be |
| // null and if so are treated as a NULL value. |
| |
| if (STRICT_JMS) |
| { |
| // JMS start character |
| if (!(Character.isJavaIdentifierStart(propertyName.charAt(0)))) |
| { |
| throw new IllegalArgumentException("Identifier '" + propertyName + "' does not start with a valid JMS identifier start character"); |
| } |
| |
| // JMS part character |
| int length = propertyName.length(); |
| for (int c = 1; c < length; c++) |
| { |
| if (!(Character.isJavaIdentifierPart(propertyName.charAt(c)))) |
| { |
| throw new IllegalArgumentException("Identifier '" + propertyName + "' contains an invalid JMS identifier character"); |
| } |
| } |
| |
| // JMS invalid names |
| if ((propertyName.equals("NULL") |
| || propertyName.equals("TRUE") |
| || propertyName.equals("FALSE") |
| || propertyName.equals("NOT") |
| || propertyName.equals("AND") |
| || propertyName.equals("OR") |
| || propertyName.equals("BETWEEN") |
| || propertyName.equals("LIKE") |
| || propertyName.equals("IN") |
| || propertyName.equals("IS") |
| || propertyName.equals("ESCAPE"))) |
| { |
| throw new IllegalArgumentException("Identifier '" + propertyName + "' is not allowed in JMS"); |
| } |
| } |
| |
| } |
| } |