blob: e071ea903bf9cb93c70ab60fa14b965b813755a7 [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.messaging;
import java.util.Collection;
import org.apache.qpid.proton.amqp.Symbol;
import org.apache.qpid.proton.amqp.UnsignedLong;
import org.apache.qpid.proton.amqp.messaging.Properties;
import org.apache.qpid.proton.codec.AMQPType;
import org.apache.qpid.proton.codec.FastPathDescribedTypeConstructor;
import org.apache.qpid.proton.codec.DecodeException;
import org.apache.qpid.proton.codec.Decoder;
import org.apache.qpid.proton.codec.DecoderImpl;
import org.apache.qpid.proton.codec.EncoderImpl;
import org.apache.qpid.proton.codec.EncodingCodes;
import org.apache.qpid.proton.codec.TypeEncoding;
import org.apache.qpid.proton.codec.WritableBuffer;
public class FastPathPropertiesType implements AMQPType<Properties>, FastPathDescribedTypeConstructor<Properties> {
private static final Object[] DESCRIPTORS =
{
UnsignedLong.valueOf(0x0000000000000073L), Symbol.valueOf("amqp:properties:list"),
};
private final PropertiesType propertiesType;
public FastPathPropertiesType(EncoderImpl encoder) {
this.propertiesType = new PropertiesType(encoder);
}
public EncoderImpl getEncoder() {
return propertiesType.getEncoder();
}
public DecoderImpl getDecoder() {
return propertiesType.getDecoder();
}
@Override
public Properties readValue() {
DecoderImpl decoder = getDecoder();
byte typeCode = decoder.getBuffer().get();
@SuppressWarnings("unused")
int size = 0;
int count = 0;
switch (typeCode) {
case EncodingCodes.LIST0:
break;
case EncodingCodes.LIST8:
size = ((int)decoder.getBuffer().get()) & 0xff;
count = ((int)decoder.getBuffer().get()) & 0xff;
break;
case EncodingCodes.LIST32:
size = decoder.getBuffer().getInt();
count = decoder.getBuffer().getInt();
break;
default:
throw new DecodeException("Incorrect type found in Properties encoding: " + typeCode);
}
Properties properties = new Properties();
for (int index = 0; index < count; ++index) {
switch (index) {
case 0:
properties.setMessageId(decoder.readObject());
break;
case 1:
properties.setUserId(decoder.readBinary());
break;
case 2:
properties.setTo(decoder.readString());
break;
case 3:
properties.setSubject(decoder.readString());
break;
case 4:
properties.setReplyTo(decoder.readString());
break;
case 5:
properties.setCorrelationId(decoder.readObject());
break;
case 6:
properties.setContentType(decoder.readSymbol());
break;
case 7:
properties.setContentEncoding(decoder.readSymbol());
break;
case 8:
properties.setAbsoluteExpiryTime(decoder.readTimestamp());
break;
case 9:
properties.setCreationTime(decoder.readTimestamp());
break;
case 10:
properties.setGroupId(decoder.readString());
break;
case 11:
properties.setGroupSequence(decoder.readUnsignedInteger());
break;
case 12:
properties.setReplyToGroupId(decoder.readString());
break;
default:
throw new IllegalStateException("To many entries in Properties encoding");
}
}
return properties;
}
@Override
public void skipValue() {
getDecoder().readConstructor().skipValue();
}
@Override
public boolean encodesJavaPrimitive() {
return false;
}
@Override
public Class<Properties> getTypeClass() {
return Properties.class;
}
@Override
public TypeEncoding<Properties> getEncoding(Properties properties) {
return propertiesType.getEncoding(properties);
}
@Override
public TypeEncoding<Properties> getCanonicalEncoding() {
return propertiesType.getCanonicalEncoding();
}
@Override
public Collection<? extends TypeEncoding<Properties>> getAllEncodings() {
return propertiesType.getAllEncodings();
}
@Override
public void write(Properties value) {
WritableBuffer buffer = getEncoder().getBuffer();
int count = getElementCount(value);
byte encodingCode = deduceEncodingCode(value, count);
buffer.put(EncodingCodes.DESCRIBED_TYPE_INDICATOR);
getEncoder().writeUnsignedLong(propertiesType.getDescriptor());
// Optimized step, no other data to be written.
if (count == 0 || encodingCode == EncodingCodes.LIST0) {
buffer.put(EncodingCodes.LIST0);
return;
}
final int fieldWidth;
if (encodingCode == EncodingCodes.LIST8) {
fieldWidth = 1;
buffer.put(EncodingCodes.LIST8);
} else {
fieldWidth = 4;
buffer.put(EncodingCodes.LIST32);
}
int startIndex = buffer.position();
// Reserve space for the size and write the count of list elements.
if (fieldWidth == 1) {
buffer.put((byte) 0);
buffer.put((byte) count);
} else {
buffer.putInt(0);
buffer.putInt(count);
}
// Write the list elements and then compute total size written.
for (int i = 0; i < count; ++i) {
writeElement(value, i);
}
// Move back and write the size
int endIndex = buffer.position();
int writeSize = endIndex - startIndex - fieldWidth;
buffer.position(startIndex);
if (fieldWidth == 1) {
buffer.put((byte) writeSize);
} else {
buffer.putInt(writeSize);
}
buffer.position(endIndex);
}
private byte deduceEncodingCode(Properties value, int elementCount) {
if (elementCount == 0) {
return EncodingCodes.LIST0;
} else {
return EncodingCodes.LIST32;
}
}
private void writeElement(Properties properties, int index) {
switch (index) {
case 0:
getEncoder().writeObject(properties.getMessageId());
break;
case 1:
getEncoder().writeBinary(properties.getUserId());
break;
case 2:
getEncoder().writeString(properties.getTo());
break;
case 3:
getEncoder().writeString(properties.getSubject());
break;
case 4:
getEncoder().writeString(properties.getReplyTo());
break;
case 5:
getEncoder().writeObject(properties.getCorrelationId());
break;
case 6:
getEncoder().writeSymbol(properties.getContentType());
break;
case 7:
getEncoder().writeSymbol(properties.getContentEncoding());
break;
case 8:
getEncoder().writeTimestamp(properties.getAbsoluteExpiryTime());
break;
case 9:
getEncoder().writeTimestamp(properties.getCreationTime());
break;
case 10:
getEncoder().writeString(properties.getGroupId());
break;
case 11:
getEncoder().writeUnsignedInteger(properties.getGroupSequence());
break;
case 12:
getEncoder().writeString(properties.getReplyToGroupId());
break;
default:
throw new IllegalArgumentException("Unknown Properties value index: " + index);
}
}
private int getElementCount(Properties properties) {
if (properties.getReplyToGroupId() != null) {
return 13;
} else if (properties.getGroupSequence() != null) {
return 12;
} else if (properties.getGroupId() != null) {
return 11;
} else if (properties.getCreationTime() != null) {
return 10;
} else if (properties.getAbsoluteExpiryTime() != null) {
return 9;
} else if (properties.getContentEncoding() != null) {
return 8;
} else if (properties.getContentType() != null) {
return 7;
} else if (properties.getCorrelationId() != null) {
return 6;
} else if (properties.getReplyTo() != null) {
return 5;
} else if (properties.getSubject() != null) {
return 4;
} else if (properties.getTo() != null) {
return 3;
} else if (properties.getUserId() != null) {
return 2;
} else if (properties.getMessageId() != null) {
return 1;
}
return 0;
}
public static void register(Decoder decoder, EncoderImpl encoder) {
FastPathPropertiesType type = new FastPathPropertiesType(encoder);
for(Object descriptor : DESCRIPTORS)
{
decoder.register(descriptor, (FastPathDescribedTypeConstructor<?>) type);
}
encoder.register(type);
}
}