| /* |
| * |
| * 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.framing; |
| |
| import java.math.BigDecimal; |
| import java.nio.ByteBuffer; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.Map; |
| |
| /** |
| * AMQTypedValue combines together a native Java Object value, and an {@link AMQType}, as a fully typed AMQP parameter |
| * value. It provides the ability to read and write fully typed parameters to and from byte buffers. It also provides |
| * the ability to create such parameters from Java native value and a type tag or to extract the native value and type |
| * from one. |
| */ |
| public abstract class AMQTypedValue |
| { |
| |
| public abstract AMQType getType(); |
| |
| public abstract Object getValue(); |
| |
| public abstract void writeToBuffer(ByteBuffer buffer); |
| |
| public abstract int getEncodingSize(); |
| |
| |
| private static final class GenericTypedValue extends AMQTypedValue |
| { |
| /** The type of the value. */ |
| private final AMQType _type; |
| |
| /** The Java native representation of the AMQP typed value. */ |
| private final Object _value; |
| |
| private GenericTypedValue(AMQType type, Object value) |
| { |
| if (type == null) |
| { |
| throw new NullPointerException("Cannot create a typed value with null type"); |
| } |
| |
| _type = type; |
| _value = type.toNativeValue(value); |
| } |
| |
| private GenericTypedValue(AMQType type, ByteBuffer buffer) |
| { |
| _type = type; |
| _value = type.readValueFromBuffer(buffer); |
| } |
| |
| |
| public AMQType getType() |
| { |
| return _type; |
| } |
| |
| public Object getValue() |
| { |
| return _value; |
| } |
| |
| public void writeToBuffer(ByteBuffer buffer) |
| { |
| _type.writeToBuffer(_value, buffer); |
| } |
| |
| public int getEncodingSize() |
| { |
| return _type.getEncodingSize(_value); |
| } |
| |
| |
| public String toString() |
| { |
| return "[" + getType() + ": " + getValue() + "]"; |
| } |
| |
| |
| public boolean equals(Object o) |
| { |
| if(o instanceof GenericTypedValue) |
| { |
| GenericTypedValue other = (GenericTypedValue) o; |
| return _type == other._type && (_value == null ? other._value == null : _value.equals(other._value)); |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| public int hashCode() |
| { |
| return _type.hashCode() ^ (_value == null ? 0 : _value.hashCode()); |
| } |
| |
| } |
| |
| private static final class LongTypedValue extends AMQTypedValue |
| { |
| |
| private final long _value; |
| |
| private LongTypedValue(long value) |
| { |
| _value = value; |
| } |
| |
| public LongTypedValue(ByteBuffer buffer) |
| { |
| _value = buffer.getLong(); |
| } |
| |
| public AMQType getType() |
| { |
| return AMQType.LONG; |
| } |
| |
| |
| public Object getValue() |
| { |
| return _value; |
| } |
| |
| public void writeToBuffer(ByteBuffer buffer) |
| { |
| buffer.put(AMQType.LONG.identifier()); |
| buffer.putLong(_value); |
| } |
| |
| |
| public int getEncodingSize() |
| { |
| return EncodingUtils.encodedLongLength(); |
| } |
| } |
| |
| private static final class IntTypedValue extends AMQTypedValue |
| { |
| @Override |
| public String toString() |
| { |
| return "[INT: " + String.valueOf(_value) + "]"; |
| } |
| |
| private final int _value; |
| |
| public IntTypedValue(int value) |
| { |
| _value = value; |
| } |
| |
| public AMQType getType() |
| { |
| return AMQType.INT; |
| } |
| |
| |
| public Object getValue() |
| { |
| return _value; |
| } |
| |
| public void writeToBuffer(ByteBuffer buffer) |
| { |
| buffer.put(AMQType.INT.identifier()); |
| buffer.putInt(_value); |
| } |
| |
| public int getEncodingSize() |
| { |
| return EncodingUtils.encodedIntegerLength(); |
| } |
| } |
| |
| |
| public static AMQTypedValue readFromBuffer(ByteBuffer buffer) |
| { |
| AMQType type = AMQTypeMap.getType(buffer.get()); |
| |
| switch(type) |
| { |
| case LONG: |
| return new LongTypedValue(buffer); |
| |
| case INT: |
| int value = buffer.getInt(); |
| return createAMQTypedValue(value); |
| |
| default: |
| return new GenericTypedValue(type, buffer); |
| } |
| |
| } |
| |
| private static final AMQTypedValue[] INT_VALUES = new AMQTypedValue[16]; |
| static |
| { |
| for(int i = 0 ; i < 16; i ++) |
| { |
| INT_VALUES[i] = new IntTypedValue(i); |
| } |
| } |
| |
| public static AMQTypedValue createAMQTypedValue(int i) |
| { |
| return (i & 0x0f) == i ? INT_VALUES[i] : new IntTypedValue(i); |
| } |
| |
| |
| public static AMQTypedValue createAMQTypedValue(long value) |
| { |
| return new LongTypedValue(value); |
| } |
| |
| public static AMQTypedValue createAMQTypedValue(AMQType type, Object value) |
| { |
| switch(type) |
| { |
| case LONG: |
| return new LongTypedValue((Long) AMQType.LONG.toNativeValue(value)); |
| case INT: |
| return new IntTypedValue((Integer) AMQType.INT.toNativeValue(value)); |
| |
| default: |
| return new GenericTypedValue(type, value); |
| } |
| } |
| |
| |
| |
| public static AMQTypedValue toTypedValue(Object val) |
| { |
| if(val == null) |
| { |
| return AMQType.VOID.asTypedValue(null); |
| } |
| |
| Class klass = val.getClass(); |
| if(klass == String.class) |
| { |
| return AMQType.LONG_STRING.asTypedValue(val); |
| } |
| else if(klass == Character.class) |
| { |
| return AMQType.ASCII_CHARACTER.asTypedValue(val); |
| } |
| else if(klass == Integer.class) |
| { |
| return AMQType.INT.asTypedValue(val); |
| } |
| else if(klass == Long.class) |
| { |
| return AMQType.LONG.asTypedValue(val); |
| } |
| else if(klass == Float.class) |
| { |
| return AMQType.FLOAT.asTypedValue(val); |
| } |
| else if(klass == Double.class) |
| { |
| return AMQType.DOUBLE.asTypedValue(val); |
| } |
| else if(klass == Date.class) |
| { |
| return AMQType.TIMESTAMP.asTypedValue(val); |
| } |
| else if(klass == Byte.class) |
| { |
| return AMQType.BYTE.asTypedValue(val); |
| } |
| else if(klass == Boolean.class) |
| { |
| return AMQType.BOOLEAN.asTypedValue(val); |
| } |
| else if(klass == byte[].class) |
| { |
| return AMQType.BINARY.asTypedValue(val); |
| } |
| else if(klass == BigDecimal.class) |
| { |
| return AMQType.DECIMAL.asTypedValue(val); |
| } |
| else if(val instanceof Map) |
| { |
| return AMQType.FIELD_TABLE.asTypedValue(FieldTable.convertToFieldTable((Map<String,Object>)val)); |
| } |
| else if(klass == FieldTable.class) |
| { |
| return AMQType.FIELD_TABLE.asTypedValue(val); |
| } |
| else if(val instanceof Collection) |
| { |
| return AMQType.FIELD_ARRAY.asTypedValue(val); |
| } |
| throw new IllegalArgumentException("Cannot convert an object of class " + val.getClass().getName() + " to an AMQP typed value"); |
| } |
| } |