blob: 512805b8de2e774f056d5e6eb048ad756e933795 [file] [log] [blame]
/*
*
* 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;
}
}