| /* |
| * |
| * 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.proton.codec; |
| |
| import java.nio.ByteBuffer; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.UUID; |
| |
| import org.apache.qpid.proton.amqp.Binary; |
| import org.apache.qpid.proton.amqp.Decimal128; |
| import org.apache.qpid.proton.amqp.Decimal32; |
| import org.apache.qpid.proton.amqp.Decimal64; |
| import org.apache.qpid.proton.amqp.DescribedType; |
| import org.apache.qpid.proton.amqp.Symbol; |
| import org.apache.qpid.proton.amqp.UnsignedByte; |
| import org.apache.qpid.proton.amqp.UnsignedInteger; |
| import org.apache.qpid.proton.amqp.UnsignedLong; |
| import org.apache.qpid.proton.amqp.UnsignedShort; |
| |
| public final class EncoderImpl implements ByteBufferEncoder |
| { |
| private static final byte DESCRIBED_TYPE_OP = (byte)0; |
| |
| private WritableBuffer _buffer; |
| |
| private final DecoderImpl _decoder; |
| private final Map<Class, AMQPType> _typeRegistry = new HashMap<Class, AMQPType>(); |
| private Map<Object, AMQPType> _describedDescriptorRegistry = new HashMap<Object, AMQPType>(); |
| private Map<Class, AMQPType> _describedTypesClassRegistry = new HashMap<Class, AMQPType>(); |
| |
| private final NullType _nullType; |
| private final BooleanType _booleanType; |
| private final ByteType _byteType; |
| private final UnsignedByteType _unsignedByteType; |
| private final ShortType _shortType; |
| private final UnsignedShortType _unsignedShortType; |
| private final IntegerType _integerType; |
| private final UnsignedIntegerType _unsignedIntegerType; |
| private final LongType _longType; |
| private final UnsignedLongType _unsignedLongType; |
| private final BigIntegerType _bigIntegerType; |
| |
| private final CharacterType _characterType; |
| private final FloatType _floatType; |
| private final DoubleType _doubleType; |
| private final TimestampType _timestampType; |
| private final UUIDType _uuidType; |
| |
| private final Decimal32Type _decimal32Type; |
| private final Decimal64Type _decimal64Type; |
| private final Decimal128Type _decimal128Type; |
| |
| private final BinaryType _binaryType; |
| private final SymbolType _symbolType; |
| private final StringType _stringType; |
| |
| private final ListType _listType; |
| private final MapType _mapType; |
| |
| private final ArrayType _arrayType; |
| |
| public EncoderImpl(DecoderImpl decoder) |
| { |
| _decoder = decoder; |
| _nullType = new NullType(this, decoder); |
| _booleanType = new BooleanType(this, decoder); |
| _byteType = new ByteType(this, decoder); |
| _unsignedByteType = new UnsignedByteType(this, decoder); |
| _shortType = new ShortType(this, decoder); |
| _unsignedShortType = new UnsignedShortType(this, decoder); |
| _integerType = new IntegerType(this, decoder); |
| _unsignedIntegerType = new UnsignedIntegerType(this, decoder); |
| _longType = new LongType(this, decoder); |
| _unsignedLongType = new UnsignedLongType(this, decoder); |
| _bigIntegerType = new BigIntegerType(this, decoder); |
| |
| _characterType = new CharacterType(this, decoder); |
| _floatType = new FloatType(this, decoder); |
| _doubleType = new DoubleType(this, decoder); |
| _timestampType = new TimestampType(this, decoder); |
| _uuidType = new UUIDType(this, decoder); |
| |
| _decimal32Type = new Decimal32Type(this, decoder); |
| _decimal64Type = new Decimal64Type(this, decoder); |
| _decimal128Type = new Decimal128Type(this, decoder); |
| |
| |
| _binaryType = new BinaryType(this, decoder); |
| _symbolType = new SymbolType(this, decoder); |
| _stringType = new StringType(this, decoder); |
| |
| _listType = new ListType(this, decoder); |
| _mapType = new MapType(this, decoder); |
| |
| _arrayType = new ArrayType(this, |
| decoder, |
| _booleanType, |
| _byteType, |
| _shortType, |
| _integerType, |
| _longType, |
| _floatType, |
| _doubleType, |
| _characterType); |
| } |
| |
| @Override |
| public void setByteBuffer(final ByteBuffer buf) |
| { |
| _buffer = new WritableBuffer.ByteBufferWrapper(buf); |
| } |
| |
| public void setByteBuffer(final WritableBuffer buf) |
| { |
| _buffer = buf; |
| } |
| |
| public WritableBuffer getBuffer() |
| { |
| return _buffer; |
| } |
| |
| public DecoderImpl getDecoder() |
| { |
| return _decoder; |
| } |
| |
| @Override |
| public AMQPType getType(final Object element) |
| { |
| return getTypeFromClass(element == null ? Void.class : element.getClass(), element); |
| } |
| |
| public AMQPType getTypeFromClass(final Class clazz) |
| { |
| return getTypeFromClass(clazz, null); |
| } |
| |
| private AMQPType getTypeFromClass(final Class clazz, Object instance) |
| { |
| AMQPType amqpType = _typeRegistry.get(clazz); |
| if(amqpType == null) |
| { |
| if(clazz.isArray()) |
| { |
| amqpType = _arrayType; |
| } |
| else |
| { |
| if(List.class.isAssignableFrom(clazz)) |
| { |
| amqpType = _listType; |
| } |
| else if(Map.class.isAssignableFrom(clazz)) |
| { |
| amqpType = _mapType; |
| } |
| else if(DescribedType.class.isAssignableFrom(clazz)) |
| { |
| amqpType = _describedTypesClassRegistry.get(clazz); |
| if(amqpType == null && instance != null) |
| { |
| Object descriptor = ((DescribedType) instance).getDescriptor(); |
| amqpType = _describedDescriptorRegistry.get(descriptor); |
| if(amqpType == null) |
| { |
| amqpType = new DynamicDescribedType(this, descriptor); |
| _describedDescriptorRegistry.put(descriptor, amqpType); |
| } |
| } |
| |
| return amqpType; |
| } |
| } |
| _typeRegistry.put(clazz, amqpType); |
| } |
| |
| return amqpType; |
| } |
| |
| @Override |
| public <V> void register(AMQPType<V> type) |
| { |
| register(type.getTypeClass(), type); |
| } |
| |
| <T> void register(Class<T> clazz, AMQPType<T> type) |
| { |
| _typeRegistry.put(clazz, type); |
| } |
| |
| public void registerDescribedType(Class clazz, Object descriptor) |
| { |
| AMQPType type = _describedDescriptorRegistry.get(descriptor); |
| if(type == null) |
| { |
| type = new DynamicDescribedType(this, descriptor); |
| _describedDescriptorRegistry.put(descriptor, type); |
| } |
| _describedTypesClassRegistry.put(clazz, type); |
| } |
| |
| @Override |
| public void writeNull() |
| { |
| _buffer.put(EncodingCodes.NULL); |
| } |
| |
| @Override |
| public void writeBoolean(final boolean bool) |
| { |
| if (bool) |
| { |
| _buffer.put(EncodingCodes.BOOLEAN_TRUE); |
| } |
| else |
| { |
| _buffer.put(EncodingCodes.BOOLEAN_FALSE); |
| } |
| } |
| |
| @Override |
| public void writeBoolean(final Boolean bool) |
| { |
| if(bool == null) |
| { |
| writeNull(); |
| } |
| else if (Boolean.TRUE.equals(bool)) |
| { |
| _buffer.put(EncodingCodes.BOOLEAN_TRUE); |
| } |
| else |
| { |
| _buffer.put(EncodingCodes.BOOLEAN_FALSE); |
| } |
| } |
| |
| @Override |
| public void writeUnsignedByte(final UnsignedByte ubyte) |
| { |
| if(ubyte == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _unsignedByteType.fastWrite(this, ubyte); |
| } |
| } |
| |
| @Override |
| public void writeUnsignedShort(final UnsignedShort ushort) |
| { |
| if(ushort == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _unsignedShortType.fastWrite(this, ushort); |
| } |
| } |
| |
| @Override |
| public void writeUnsignedInteger(final UnsignedInteger uint) |
| { |
| if(uint == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _unsignedIntegerType.fastWrite(this, uint); |
| } |
| } |
| |
| @Override |
| public void writeUnsignedLong(final UnsignedLong ulong) |
| { |
| if(ulong == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _unsignedLongType.fastWrite(this, ulong); |
| } |
| } |
| |
| @Override |
| public void writeByte(final byte b) |
| { |
| _byteType.write(b); |
| } |
| |
| @Override |
| public void writeByte(final Byte b) |
| { |
| if(b == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| writeByte(b.byteValue()); |
| } |
| } |
| |
| @Override |
| public void writeShort(final short s) |
| { |
| _shortType.write(s); |
| } |
| |
| @Override |
| public void writeShort(final Short s) |
| { |
| if(s == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| writeShort(s.shortValue()); |
| } |
| } |
| |
| @Override |
| public void writeInteger(final int i) |
| { |
| _integerType.write(i); |
| } |
| |
| @Override |
| public void writeInteger(final Integer i) |
| { |
| if(i == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| writeInteger(i.intValue()); |
| } |
| } |
| |
| @Override |
| public void writeLong(final long l) |
| { |
| _longType.write(l); |
| } |
| |
| @Override |
| public void writeLong(final Long l) |
| { |
| |
| if(l == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| writeLong(l.longValue()); |
| } |
| } |
| |
| @Override |
| public void writeFloat(final float f) |
| { |
| _floatType.write(f); |
| } |
| |
| @Override |
| public void writeFloat(final Float f) |
| { |
| if(f == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| writeFloat(f.floatValue()); |
| } |
| } |
| |
| @Override |
| public void writeDouble(final double d) |
| { |
| _doubleType.write(d); |
| } |
| |
| @Override |
| public void writeDouble(final Double d) |
| { |
| if(d == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| writeDouble(d.doubleValue()); |
| } |
| } |
| |
| @Override |
| public void writeDecimal32(final Decimal32 d) |
| { |
| if(d == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _decimal32Type.write(d); |
| } |
| } |
| |
| @Override |
| public void writeDecimal64(final Decimal64 d) |
| { |
| if(d == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _decimal64Type.write(d); |
| } |
| } |
| |
| @Override |
| public void writeDecimal128(final Decimal128 d) |
| { |
| if(d == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _decimal128Type.write(d); |
| } |
| } |
| |
| @Override |
| public void writeCharacter(final char c) |
| { |
| // TODO - java character may be half of a pair, should probably throw exception then |
| _characterType.write(c); |
| } |
| |
| @Override |
| public void writeCharacter(final Character c) |
| { |
| if(c == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| writeCharacter(c.charValue()); |
| } |
| } |
| |
| @Override |
| public void writeTimestamp(final long timestamp) |
| { |
| _timestampType.fastWrite(this, timestamp); |
| } |
| |
| @Override |
| public void writeTimestamp(final Date d) |
| { |
| if(d == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _timestampType.fastWrite(this, d.getTime()); |
| } |
| } |
| |
| @Override |
| public void writeUUID(final UUID uuid) |
| { |
| if(uuid == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _uuidType.fastWrite(this, uuid); |
| } |
| |
| } |
| |
| @Override |
| public void writeBinary(final Binary b) |
| { |
| if(b == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _binaryType.fastWrite(this, b); |
| } |
| } |
| |
| @Override |
| public void writeString(final String s) |
| { |
| if(s == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _stringType.write(s); |
| } |
| } |
| |
| @Override |
| public void writeSymbol(final Symbol s) |
| { |
| if(s == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _symbolType.fastWrite(this, s); |
| } |
| |
| } |
| |
| @Override |
| public void writeList(final List l) |
| { |
| if(l == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _listType.write(l); |
| } |
| } |
| |
| @Override |
| public void writeMap(final Map m) |
| { |
| |
| if(m == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _mapType.write(m); |
| } |
| } |
| |
| @Override |
| public void writeDescribedType(final DescribedType d) |
| { |
| if(d == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _buffer.put(DESCRIBED_TYPE_OP); |
| writeObject(d.getDescriptor()); |
| writeObject(d.getDescribed()); |
| } |
| } |
| |
| @Override |
| public void writeArray(final boolean[] a) |
| { |
| if(a == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _arrayType.write(a); |
| } |
| } |
| |
| @Override |
| public void writeArray(final byte[] a) |
| { |
| if(a == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _arrayType.write(a); |
| } |
| } |
| |
| @Override |
| public void writeArray(final short[] a) |
| { |
| if(a == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _arrayType.write(a); |
| } |
| } |
| |
| @Override |
| public void writeArray(final int[] a) |
| { |
| if(a == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _arrayType.write(a); |
| } |
| } |
| |
| @Override |
| public void writeArray(final long[] a) |
| { |
| if(a == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _arrayType.write(a); |
| } |
| } |
| |
| @Override |
| public void writeArray(final float[] a) |
| { |
| if(a == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _arrayType.write(a); |
| } |
| } |
| |
| @Override |
| public void writeArray(final double[] a) |
| { |
| if(a == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _arrayType.write(a); |
| } |
| } |
| |
| @Override |
| public void writeArray(final char[] a) |
| { |
| if(a == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _arrayType.write(a); |
| } |
| } |
| |
| @Override |
| public void writeArray(final Object[] a) |
| { |
| if(a == null) |
| { |
| writeNull(); |
| } |
| else |
| { |
| _arrayType.write(a); |
| } |
| } |
| |
| @Override |
| public void writeObject(final Object o) |
| { |
| if (o == null) |
| { |
| getBuffer().put(EncodingCodes.NULL); |
| return; |
| } |
| |
| AMQPType type = _typeRegistry.get(o.getClass()); |
| |
| if(type == null) |
| { |
| if(o.getClass().isArray()) |
| { |
| writeArrayType(o); |
| } |
| else if(o instanceof List) |
| { |
| writeList((List)o); |
| } |
| else if(o instanceof Map) |
| { |
| writeMap((Map)o); |
| } |
| else if(o instanceof DescribedType) |
| { |
| writeDescribedType((DescribedType)o); |
| } |
| else |
| { |
| throw new IllegalArgumentException( |
| "Do not know how to write Objects of class " + o.getClass().getName()); |
| } |
| } |
| else |
| { |
| type.write(o); |
| } |
| } |
| |
| private void writeArrayType(Object array) { |
| Class<?> componentType = array.getClass().getComponentType(); |
| if(componentType.isPrimitive()) |
| { |
| if(componentType == Boolean.TYPE) |
| { |
| writeArray((boolean[])array); |
| } |
| else if(componentType == Byte.TYPE) |
| { |
| writeArray((byte[])array); |
| } |
| else if(componentType == Short.TYPE) |
| { |
| writeArray((short[])array); |
| } |
| else if(componentType == Integer.TYPE) |
| { |
| writeArray((int[])array); |
| } |
| else if(componentType == Long.TYPE) |
| { |
| writeArray((long[])array); |
| } |
| else if(componentType == Float.TYPE) |
| { |
| writeArray((float[])array); |
| } |
| else if(componentType == Double.TYPE) |
| { |
| writeArray((double[])array); |
| } |
| else if(componentType == Character.TYPE) |
| { |
| writeArray((char[])array); |
| } |
| else |
| { |
| throw new IllegalArgumentException("Cannot write arrays of type " + componentType.getName()); |
| } |
| } |
| else |
| { |
| writeArray((Object[]) array); |
| } |
| } |
| |
| public void writeRaw(final byte b) |
| { |
| _buffer.put(b); |
| } |
| |
| void writeRaw(final short s) |
| { |
| _buffer.putShort(s); |
| } |
| |
| void writeRaw(final int i) |
| { |
| _buffer.putInt(i); |
| } |
| |
| void writeRaw(final long l) |
| { |
| _buffer.putLong(l); |
| } |
| |
| void writeRaw(final float f) |
| { |
| _buffer.putFloat(f); |
| } |
| |
| void writeRaw(final double d) |
| { |
| _buffer.putDouble(d); |
| } |
| |
| void writeRaw(byte[] src, int offset, int length) |
| { |
| _buffer.put(src, offset, length); |
| } |
| |
| void writeRaw(final String string) |
| { |
| _buffer.put(string); |
| } |
| |
| AMQPType getNullTypeEncoder() |
| { |
| return _nullType; |
| } |
| } |