/**
* 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.activemq.artemis.core.message.impl;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.Set;
import io.netty.buffer.ByteBuf;
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
import org.apache.activemq.artemis.api.core.ActiveMQBuffers;
import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.api.core.ActiveMQPropertyConversionException;
import org.apache.activemq.artemis.api.core.ICoreMessage;
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.api.core.RefCountMessage;
import org.apache.activemq.artemis.api.core.RoutingType;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.buffers.impl.ChannelBufferWrapper;
import org.apache.activemq.artemis.core.buffers.impl.ResetLimitWrappedActiveMQBuffer;
import org.apache.activemq.artemis.core.message.LargeBodyEncoder;
import org.apache.activemq.artemis.core.persistence.Persister;
import org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl;
import org.apache.activemq.artemis.reader.MessageUtil;
import org.apache.activemq.artemis.utils.DataConstants;
import org.apache.activemq.artemis.utils.UUID;
import org.apache.activemq.artemis.utils.collections.TypedProperties;
import org.jboss.logging.Logger;
/** Note: you shouldn't change properties using multi-threads. Change your properties before you can send it to multiple
* consumers */
public class CoreMessage extends RefCountMessage implements ICoreMessage {
public static final int BUFFER_HEADER_SPACE = PacketImpl.PACKET_HEADERS_SIZE;
private volatile int memoryEstimate = -1;
private static final Logger logger = Logger.getLogger(CoreMessage.class);
// There's an integer with the number of bytes for the body
public static final int BODY_OFFSET = DataConstants.SIZE_INT;
/** That is the encode for the whole message, including properties..
it does not include the buffer for the Packet send and receive header on core protocol */
protected ByteBuf buffer;
private volatile boolean validBuffer = false;
protected volatile ResetLimitWrappedActiveMQBuffer writableBuffer;
Object body;
protected int endOfBodyPosition = -1;
protected int messageIDPosition = -1;
protected long messageID;
protected SimpleString address;
protected byte type;
protected boolean durable;
/**
* GMT milliseconds at which this message expires. 0 means never expires *
*/
private long expiration;
protected long timestamp;
protected byte priority;
private UUID userID;
private int propertiesLocation = -1;
protected volatile TypedProperties properties;
public CoreMessage() {
}
/** On core there's no delivery annotation */
@Override
public Object getAnnotation(SimpleString key) {
return getObjectProperty(key);
}
/** On core there's no delivery annotation */
@Override
public Object removeAnnotation(SimpleString key) {
return removeProperty(key);
}
@Override
public void cleanupInternalProperties() {
if (properties.hasInternalProperties()) {
LinkedList<SimpleString> valuesToRemove = null;
for (SimpleString name : getPropertyNames()) {
// We use properties to establish routing context on clustering.
// However if the client resends the message after receiving, it needs to be removed
if ((name.startsWith(Message.HDR_ROUTE_TO_IDS) && !name.equals(Message.HDR_ROUTE_TO_IDS)) || (name.startsWith(Message.HDR_ROUTE_TO_ACK_IDS) && !name.equals(Message.HDR_ROUTE_TO_ACK_IDS))) {
if (valuesToRemove == null) {
valuesToRemove = new LinkedList<>();
}
valuesToRemove.add(name);
}
}
if (valuesToRemove != null) {
for (SimpleString removal : valuesToRemove) {
this.removeProperty(removal);
}
}
}
}
@Override
public Persister<Message> getPersister() {
return CoreMessagePersister.getInstance();
}
public CoreMessage initBuffer(final int initialMessageBufferSize) {
buffer = ActiveMQBuffers.dynamicBuffer(initialMessageBufferSize).byteBuf();
// There's a bug in netty which means a dynamic buffer won't resize until you write a byte
buffer.writeByte((byte) 0);
buffer.setIndex(BODY_OFFSET, BODY_OFFSET);
return this;
}
@Override
public SimpleString getReplyTo() {
return getSimpleStringProperty(MessageUtil.REPLYTO_HEADER_NAME);
}
@Override
public RoutingType getRoutingType() {
if (containsProperty(Message.HDR_ROUTING_TYPE)) {
return RoutingType.getType(getByteProperty(Message.HDR_ROUTING_TYPE));
}
return null;
}
@Override
public Message setRoutingType(RoutingType routingType) {
if (routingType == null) {
removeProperty(Message.HDR_ROUTING_TYPE);
} else {
putByteProperty(Message.HDR_ROUTING_TYPE, routingType.getType());
}
return this;
}
@Override
public CoreMessage setReplyTo(SimpleString address) {
if (address == null) {
checkProperties();
properties.removeProperty(MessageUtil.REPLYTO_HEADER_NAME);
} else {
putStringProperty(MessageUtil.REPLYTO_HEADER_NAME, address);
}
return this;
}
@Override
public void receiveBuffer(ByteBuf buffer) {
this.buffer = buffer;
this.buffer.retain();
decode();
this.validBuffer = true;
}
@Override
public ActiveMQBuffer getReadOnlyBodyBuffer() {
checkEncode();
internalWritableBuffer();
return new ChannelBufferWrapper(buffer.slice(BODY_OFFSET, endOfBodyPosition - BUFFER_HEADER_SPACE).setIndex(0, endOfBodyPosition - BUFFER_HEADER_SPACE).asReadOnly());
}
@Override
public SimpleString getGroupID() {
return this.getSimpleStringProperty(Message.HDR_GROUP_ID);
}
/**
*
* @param sendBuffer
* @param deliveryCount Some protocols (AMQP) will have this as part of the message. ignored on core
*/
@Override
public void sendBuffer(ByteBuf sendBuffer, int deliveryCount) {
checkEncode();
sendBuffer.writeBytes(buffer, 0, buffer.writerIndex());
}
private synchronized void checkEncode() {
if (!validBuffer) {
encode();
}
}
@Override
public Long getScheduledDeliveryTime() {
checkProperties();
Object property = getObjectProperty(Message.HDR_SCHEDULED_DELIVERY_TIME);
if (property != null && property instanceof Number) {
return ((Number) property).longValue();
}
return 0L;
}
@Override
public CoreMessage setScheduledDeliveryTime(Long time) {
checkProperties();
if (time == null || time == 0) {
removeProperty(Message.HDR_SCHEDULED_DELIVERY_TIME);
} else {
putLongProperty(Message.HDR_SCHEDULED_DELIVERY_TIME, time);
}
return this;
}
@Override
public InputStream getBodyInputStream() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public ActiveMQBuffer getBodyBuffer() {
// if using the writable buffer, we must parse properties
checkProperties();
internalWritableBuffer();
return writableBuffer;
}
private void internalWritableBuffer() {
if (writableBuffer == null) {
writableBuffer = new ResetLimitWrappedActiveMQBuffer(BODY_OFFSET, buffer.duplicate(), this);
if (endOfBodyPosition > 0) {
writableBuffer.byteBuf().setIndex(BODY_OFFSET, endOfBodyPosition - BUFFER_HEADER_SPACE + BODY_OFFSET);
writableBuffer.resetReaderIndex();
}
}
}
@Override
public int getEndOfBodyPosition() {
if (endOfBodyPosition < 0) {
endOfBodyPosition = getBodyBuffer().writerIndex();
}
return endOfBodyPosition;
}
public TypedProperties getTypedProperties() {
return checkProperties();
}
@Override
public void messageChanged() {
validBuffer = false;
}
protected CoreMessage(CoreMessage other) {
this(other, other.properties);
}
public CoreMessage(long id, int bufferSize) {
this.initBuffer(bufferSize);
this.setMessageID(id);
}
protected CoreMessage(CoreMessage other, TypedProperties copyProperties) {
this.body = other.body;
this.endOfBodyPosition = other.endOfBodyPosition;
this.messageID = other.messageID;
this.address = other.address;
this.type = other.type;
this.durable = other.durable;
this.expiration = other.expiration;
this.timestamp = other.timestamp;
this.priority = other.priority;
this.userID = other.userID;
if (copyProperties != null) {
this.properties = new TypedProperties(copyProperties);
}
if (other.buffer != null) {
this.buffer = other.buffer.copy();
}
}
@Override
public void copyHeadersAndProperties(final Message msg) {
messageID = msg.getMessageID();
address = msg.getAddressSimpleString();
userID = (UUID)msg.getUserID();
type = msg.toCore().getType();
durable = msg.isDurable();
expiration = msg.getExpiration();
timestamp = msg.getTimestamp();
priority = msg.getPriority();
if (msg instanceof CoreMessage) {
properties = ((CoreMessage)msg).getTypedProperties();
}
}
@Override
public Message copy() {
checkEncode();
return new CoreMessage(this);
}
@Override
public Message copy(long newID) {
return copy().setMessageID(newID);
}
@Override
public long getExpiration() {
return expiration;
}
@Override
public long getTimestamp() {
return timestamp;
}
@Override
public CoreMessage setTimestamp(long timestamp) {
this.timestamp = timestamp;
return this;
}
@Override
public long getMessageID() {
return messageID;
}
@Override
public byte getPriority() {
return priority;
}
@Override
public UUID getUserID() {
return userID;
}
@Override
public CoreMessage setUserID(Object uuid) {
this.userID = (UUID)uuid;
return this;
}
@Override
public String getValidatedUserID() {
return getStringProperty(Message.HDR_VALIDATED_USER);
}
@Override
public CoreMessage setValidatedUserID(String validatedUserID) {
putStringProperty(Message.HDR_VALIDATED_USER, SimpleString.toSimpleString(validatedUserID));
return this;
}
@Override
public CoreMessage setMessageID(long messageID) {
this.messageID = messageID;
if (messageIDPosition >= 0 && validBuffer) {
buffer.setLong(messageIDPosition, messageID);
}
return this;
}
@Override
public CoreMessage setAddress(SimpleString address) {
if (validBuffer && !address.equals(this.address)) {
messageChanged();
}
this.address = address;
return this;
}
@Override
public SimpleString getAddressSimpleString() {
return address;
}
@Override
public CoreMessage setExpiration(long expiration) {
this.expiration = expiration;
messageChanged();
return this;
}
@Override
public CoreMessage setPriority(byte priority) {
this.priority = priority;
messageChanged();
return this;
}
public CoreMessage setUserID(UUID userID) {
this.userID = userID;
messageChanged();
return this;
}
/**
* I am keeping this synchronized as the decode of the Properties is lazy
*/
protected TypedProperties checkProperties() {
if (properties == null) {
TypedProperties properties = new TypedProperties();
if (buffer != null && propertiesLocation >= 0) {
properties.decode(buffer.duplicate().readerIndex(propertiesLocation));
}
this.properties = properties;
}
return this.properties;
}
@Override
public int getMemoryEstimate() {
if (memoryEstimate == -1) {
memoryEstimate = memoryOffset +
(buffer != null ? buffer.capacity() : 0) +
(properties != null ? properties.getMemoryOffset() : 0);
}
return memoryEstimate;
}
@Override
public boolean isServerMessage() {
// even though CoreMessage is used both on server and client
// callers are interested in knowing if this is a server large message
// as it will be used to send the body from the files.
//
// this may need further refactoring when we improve large messages
// and expose that functionality to other protocols.
return false;
}
@Override
public byte getType() {
return type;
}
@Override
public CoreMessage setType(byte type) {
this.type = type;
return this;
}
private void decode() {
endOfBodyPosition = buffer.readInt();
buffer.skipBytes(endOfBodyPosition - BUFFER_HEADER_SPACE);
decodeHeadersAndProperties(buffer, true);
buffer.readerIndex(0);
internalWritableBuffer();
}
public void decodeHeadersAndProperties(final ByteBuf buffer) {
decodeHeadersAndProperties(buffer, false);
}
private void decodeHeadersAndProperties(final ByteBuf buffer, boolean lazyProperties) {
messageIDPosition = buffer.readerIndex();
messageID = buffer.readLong();
address = SimpleString.readNullableSimpleString(buffer);
if (buffer.readByte() == DataConstants.NOT_NULL) {
byte[] bytes = new byte[16];
buffer.readBytes(bytes);
userID = new UUID(UUID.TYPE_TIME_BASED, bytes);
} else {
userID = null;
}
type = buffer.readByte();
durable = buffer.readBoolean();
expiration = buffer.readLong();
timestamp = buffer.readLong();
priority = buffer.readByte();
if (lazyProperties) {
properties = null;
propertiesLocation = buffer.readerIndex();
} else {
properties = new TypedProperties();
properties.decode(buffer);
}
}
public synchronized CoreMessage encode() {
checkProperties();
if (writableBuffer != null) {
// The message encode takes into consideration the PacketImpl which is not part of this encoding
// so we always need to take the BUFFER_HEADER_SPACE from packet impl into consideration
endOfBodyPosition = writableBuffer.writerIndex() + BUFFER_HEADER_SPACE - 4;
} else if (endOfBodyPosition <= 0) {
endOfBodyPosition = BUFFER_HEADER_SPACE + DataConstants.SIZE_INT;
}
buffer.setIndex(0, 0);
buffer.writeInt(endOfBodyPosition);
// The end of body position
buffer.writerIndex(endOfBodyPosition - BUFFER_HEADER_SPACE + DataConstants.SIZE_INT);
encodeHeadersAndProperties(buffer);
validBuffer = true;
return this;
}
public void encodeHeadersAndProperties(final ByteBuf buffer) {
checkProperties();
messageIDPosition = buffer.writerIndex();
buffer.writeLong(messageID);
SimpleString.writeNullableSimpleString(buffer, address);
if (userID == null) {
buffer.writeByte(DataConstants.NULL);
} else {
buffer.writeByte(DataConstants.NOT_NULL);
buffer.writeBytes(userID.asBytes());
}
buffer.writeByte(type);
buffer.writeBoolean(durable);
buffer.writeLong(expiration);
buffer.writeLong(timestamp);
buffer.writeByte(priority);
properties.encode(buffer);
}
@Override
public int getHeadersAndPropertiesEncodeSize() {
return DataConstants.SIZE_LONG + // Message ID
DataConstants.SIZE_BYTE + // user id null?
(userID == null ? 0 : 16) +
/* address */SimpleString.sizeofNullableString(address) +
DataConstants./* Type */SIZE_BYTE +
DataConstants./* Durable */SIZE_BOOLEAN +
DataConstants./* Expiration */SIZE_LONG +
DataConstants./* Timestamp */SIZE_LONG +
DataConstants./* Priority */SIZE_BYTE +
/* PropertySize and Properties */checkProperties().getEncodeSize();
}
@Override
public Object getDuplicateProperty() {
return getObjectProperty(Message.HDR_DUPLICATE_DETECTION_ID);
}
@Override
public SimpleString getLastValueProperty() {
return getSimpleStringProperty(Message.HDR_LAST_VALUE_NAME);
}
@Override
public int getEncodeSize() {
checkEncode();
return buffer == null ? -1 : buffer.writerIndex();
}
@Override
public boolean isLargeMessage() {
return false;
}
@Override
public String getAddress() {
if (address == null) {
return null;
} else {
return address.toString();
}
}
@Override
public CoreMessage setAddress(String address) {
messageChanged();
this.address = SimpleString.toSimpleString(address);
return this;
}
@Override
public CoreMessage setBuffer(ByteBuf buffer) {
this.buffer = buffer;
return this;
}
@Override
public ByteBuf getBuffer() {
return buffer;
}
@Override
public boolean isDurable() {
return durable;
}
@Override
public CoreMessage setDurable(boolean durable) {
messageChanged();
this.durable = durable;
return this;
}
@Override
public CoreMessage putBooleanProperty(final String key, final boolean value) {
messageChanged();
checkProperties();
properties.putBooleanProperty(new SimpleString(key), value);
return this;
}
@Override
public CoreMessage putBooleanProperty(final SimpleString key, final boolean value) {
messageChanged();
checkProperties();
properties.putBooleanProperty(key, value);
return this;
}
@Override
public Boolean getBooleanProperty(final SimpleString key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getBooleanProperty(key);
}
@Override
public Boolean getBooleanProperty(final String key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getBooleanProperty(new SimpleString(key));
}
@Override
public CoreMessage putByteProperty(final SimpleString key, final byte value) {
messageChanged();
checkProperties();
properties.putByteProperty(key, value);
return this;
}
@Override
public CoreMessage putByteProperty(final String key, final byte value) {
messageChanged();
checkProperties();
properties.putByteProperty(new SimpleString(key), value);
return this;
}
@Override
public Byte getByteProperty(final SimpleString key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getByteProperty(key);
}
@Override
public Byte getByteProperty(final String key) throws ActiveMQPropertyConversionException {
return getByteProperty(SimpleString.toSimpleString(key));
}
@Override
public CoreMessage putBytesProperty(final SimpleString key, final byte[] value) {
messageChanged();
checkProperties();
properties.putBytesProperty(key, value);
return this;
}
@Override
public CoreMessage putBytesProperty(final String key, final byte[] value) {
messageChanged();
checkProperties();
properties.putBytesProperty(new SimpleString(key), value);
return this;
}
@Override
public byte[] getBytesProperty(final SimpleString key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getBytesProperty(key);
}
@Override
public byte[] getBytesProperty(final String key) throws ActiveMQPropertyConversionException {
return getBytesProperty(new SimpleString(key));
}
@Override
public CoreMessage putCharProperty(SimpleString key, char value) {
messageChanged();
checkProperties();
properties.putCharProperty(key, value);
return this;
}
@Override
public CoreMessage putCharProperty(String key, char value) {
messageChanged();
checkProperties();
properties.putCharProperty(new SimpleString(key), value);
return this;
}
@Override
public CoreMessage putShortProperty(final SimpleString key, final short value) {
messageChanged();
checkProperties();
properties.putShortProperty(key, value);
return this;
}
@Override
public CoreMessage putShortProperty(final String key, final short value) {
messageChanged();
checkProperties();
properties.putShortProperty(new SimpleString(key), value);
return this;
}
@Override
public CoreMessage putIntProperty(final SimpleString key, final int value) {
messageChanged();
checkProperties();
properties.putIntProperty(key, value);
return this;
}
@Override
public CoreMessage putIntProperty(final String key, final int value) {
messageChanged();
checkProperties();
properties.putIntProperty(new SimpleString(key), value);
return this;
}
@Override
public Integer getIntProperty(final SimpleString key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getIntProperty(key);
}
@Override
public Integer getIntProperty(final String key) throws ActiveMQPropertyConversionException {
return getIntProperty(SimpleString.toSimpleString(key));
}
@Override
public CoreMessage putLongProperty(final SimpleString key, final long value) {
messageChanged();
checkProperties();
properties.putLongProperty(key, value);
return this;
}
@Override
public CoreMessage putLongProperty(final String key, final long value) {
messageChanged();
checkProperties();
properties.putLongProperty(new SimpleString(key), value);
return this;
}
@Override
public Long getLongProperty(final SimpleString key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getLongProperty(key);
}
@Override
public Long getLongProperty(final String key) throws ActiveMQPropertyConversionException {
checkProperties();
return getLongProperty(SimpleString.toSimpleString(key));
}
@Override
public CoreMessage putFloatProperty(final SimpleString key, final float value) {
messageChanged();
checkProperties();
properties.putFloatProperty(key, value);
return this;
}
@Override
public CoreMessage putFloatProperty(final String key, final float value) {
messageChanged();
checkProperties();
properties.putFloatProperty(new SimpleString(key), value);
return this;
}
@Override
public CoreMessage putDoubleProperty(final SimpleString key, final double value) {
messageChanged();
checkProperties();
properties.putDoubleProperty(key, value);
return this;
}
@Override
public CoreMessage putDoubleProperty(final String key, final double value) {
messageChanged();
checkProperties();
properties.putDoubleProperty(new SimpleString(key), value);
return this;
}
@Override
public Double getDoubleProperty(final SimpleString key) throws ActiveMQPropertyConversionException {
messageChanged();
checkProperties();
return properties.getDoubleProperty(key);
}
@Override
public Double getDoubleProperty(final String key) throws ActiveMQPropertyConversionException {
checkProperties();
return getDoubleProperty(SimpleString.toSimpleString(key));
}
@Override
public CoreMessage putStringProperty(final SimpleString key, final SimpleString value) {
messageChanged();
checkProperties();
properties.putSimpleStringProperty(key, value);
return this;
}
@Override
public CoreMessage putStringProperty(final String key, final String value) {
messageChanged();
checkProperties();
properties.putSimpleStringProperty(new SimpleString(key), SimpleString.toSimpleString(value));
return this;
}
@Override
public CoreMessage putObjectProperty(final SimpleString key,
final Object value) throws ActiveMQPropertyConversionException {
messageChanged();
checkProperties();
TypedProperties.setObjectProperty(key, value, properties);
return this;
}
@Override
public Object getObjectProperty(final String key) {
checkProperties();
return getObjectProperty(SimpleString.toSimpleString(key));
}
@Override
public Object getObjectProperty(final SimpleString key) {
checkProperties();
return properties.getProperty(key);
}
@Override
public CoreMessage putObjectProperty(final String key, final Object value) throws ActiveMQPropertyConversionException {
messageChanged();
putObjectProperty(new SimpleString(key), value);
return this;
}
@Override
public Short getShortProperty(final SimpleString key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getShortProperty(key);
}
@Override
public Short getShortProperty(final String key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getShortProperty(new SimpleString(key));
}
@Override
public Float getFloatProperty(final SimpleString key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getFloatProperty(key);
}
@Override
public Float getFloatProperty(final String key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getFloatProperty(new SimpleString(key));
}
@Override
public String getStringProperty(final SimpleString key) throws ActiveMQPropertyConversionException {
SimpleString str = getSimpleStringProperty(key);
if (str == null) {
return null;
} else {
return str.toString();
}
}
@Override
public String getStringProperty(final String key) throws ActiveMQPropertyConversionException {
return getStringProperty(new SimpleString(key));
}
@Override
public SimpleString getSimpleStringProperty(final SimpleString key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getSimpleStringProperty(key);
}
@Override
public SimpleString getSimpleStringProperty(final String key) throws ActiveMQPropertyConversionException {
checkProperties();
return properties.getSimpleStringProperty(new SimpleString(key));
}
@Override
public Object removeProperty(final SimpleString key) {
checkProperties();
Object oldValue = properties.removeProperty(key);
if (oldValue != null) {
messageChanged();
}
return oldValue;
}
@Override
public Object removeProperty(final String key) {
messageChanged();
checkProperties();
Object oldValue = properties.removeProperty(new SimpleString(key));
if (oldValue != null) {
messageChanged();
}
return oldValue;
}
@Override
public boolean containsProperty(final SimpleString key) {
checkProperties();
return properties.containsProperty(key);
}
@Override
public boolean containsProperty(final String key) {
checkProperties();
return properties.containsProperty(new SimpleString(key));
}
@Override
public Set<SimpleString> getPropertyNames() {
checkProperties();
return properties.getPropertyNames();
}
@Override
public LargeBodyEncoder getBodyEncoder() throws ActiveMQException {
return new DecodingContext();
}
private final class DecodingContext implements LargeBodyEncoder {
private int lastPos = 0;
private DecodingContext() {
}
@Override
public void open() {
}
@Override
public void close() {
}
@Override
public long getLargeBodySize() {
return buffer.writerIndex();
}
@Override
public int encode(final ByteBuffer bufferRead) throws ActiveMQException {
ActiveMQBuffer buffer = ActiveMQBuffers.wrappedBuffer(bufferRead);
return encode(buffer, bufferRead.capacity());
}
@Override
public int encode(final ActiveMQBuffer bufferOut, final int size) {
bufferOut.byteBuf().writeBytes(buffer, lastPos, size);
lastPos += size;
return size;
}
}
@Override
public int getPersistSize() {
checkEncode();
return buffer.writerIndex() + DataConstants.SIZE_INT;
}
@Override
public void persist(ActiveMQBuffer targetRecord) {
checkEncode();
targetRecord.writeInt(buffer.writerIndex());
targetRecord.writeBytes(buffer, 0, buffer.writerIndex());
}
@Override
public void reloadPersistence(ActiveMQBuffer record) {
int size = record.readInt();
initBuffer(size);
buffer.setIndex(0, 0).writeBytes(record.byteBuf(), size);
decode();
}
@Override
public CoreMessage toCore() {
return this;
}
@Override
public String toString() {
try {
return "CoreMessage[messageID=" + messageID + ",durable=" + isDurable() + ",userID=" + getUserID() + ",priority=" + this.getPriority() +
", timestamp=" + toDate(getTimestamp()) + ",expiration=" + toDate(getExpiration()) +
", durable=" + durable + ", address=" + getAddress() + ",properties=" + properties.toString() + "]@" + System.identityHashCode(this);
} catch (Throwable e) {
return "ServerMessage[messageID=" + messageID + "]";
}
}
private static String toDate(long timestamp) {
if (timestamp == 0) {
return "0";
} else {
return new java.util.Date(timestamp).toString();
}
}
}