com.amazon.sqs.javamessaging.message.SQSBytesMessage Maven / Gradle / Ivy
Show all versions of amazon-sqs-java-messaging-lib Show documentation
/*
* Copyright 2010-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazon.sqs.javamessaging.message;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.Arrays;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.MessageEOFException;
import javax.jms.MessageFormatException;
import javax.jms.MessageNotReadableException;
import javax.jms.MessageNotWriteableException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.amazon.sqs.javamessaging.acknowledge.Acknowledger;
import com.amazonaws.util.Base64;
import com.amazonaws.services.sqs.model.Message;
/**
* This class borrows from ActiveMQStreamMessage
, which is also
* licensed under Apache2.0. Its methods are based largely on those found in
* java.io.DataInputStream
and
* java.io.DataOutputStream
.
*
* @see org.apache.activemq.command.ActiveMQStreamMessage
*/
public class SQSBytesMessage extends SQSMessage implements BytesMessage {
private static final Log LOG = LogFactory.getLog(SQSBytesMessage.class);
private byte[] bytes;
private ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
private DataInputStream dataIn;
private DataOutputStream dataOut = new DataOutputStream(bytesOut);
/**
* Convert received SQSMessage into BytesMessage.
*/
public SQSBytesMessage(Acknowledger acknowledger, String queueUrl, Message sqsMessage) throws JMSException {
super(acknowledger, queueUrl, sqsMessage);
try {
/** Bytes is set by the reset() */
dataOut.write(Base64.decode(sqsMessage.getBody()));
/** Makes it read-only */
reset();
} catch (IOException e) {
LOG.error("IOException: Message cannot be written", e);
throw convertExceptionToJMSException(e);
} catch (Exception e) {
LOG.error("Unexpected exception: ", e);
throw convertExceptionToJMSException(e);
}
}
/**
* Create new empty BytesMessage to send.
*/
public SQSBytesMessage() throws JMSException {
super();
}
/**
* Gets the number of bytes of the message body when the message is in
* read-only mode. The value returned can be used to allocate a byte array.
* The value returned is the entire length of the message body, regardless
* of where the pointer for reading the message is currently located.
*
* @return number of bytes in the message
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public long getBodyLength() throws JMSException {
checkCanRead();
return bytes.length;
}
/**
* Reads a boolean
from the bytes message stream.
*
* @return the boolean
value
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public boolean readBoolean() throws JMSException {
checkCanRead();
try {
return dataIn.readBoolean();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads a signed 8-bit value from the bytes message stream.
*
* @return the next byte from the bytes message stream as a signed 8-bit
* byte
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public byte readByte() throws JMSException {
checkCanRead();
try {
return dataIn.readByte();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads an unsigned 8-bit value from the bytes message stream.
*
* @return the next byte from the bytes message stream, interpreted as an
* unsigned 8-bit number
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public int readUnsignedByte() throws JMSException {
checkCanRead();
try {
return dataIn.readUnsignedByte();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads a signed 16-bit number from the bytes message stream.
*
* @return the next two bytes from the bytes message stream, interpreted as
* a signed 16-bit number
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public short readShort() throws JMSException {
checkCanRead();
try {
return dataIn.readShort();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads an unsigned 16-bit number from the bytes message stream.
*
* @return the next two bytes from the bytes message stream, interpreted as
* an unsigned 16-bit integer
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public int readUnsignedShort() throws JMSException {
checkCanRead();
try {
return dataIn.readUnsignedShort();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads a Unicode character value from the bytes message stream.
*
* @return a Unicode character from the bytes message stream
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public char readChar() throws JMSException {
checkCanRead();
try {
return dataIn.readChar();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads a 32-bit integer from the bytes message stream.
*
* @return the next four bytes from the bytes message stream, interpreted as an int
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public int readInt() throws JMSException {
checkCanRead();
try {
return dataIn.readInt();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads a 64-bit integer from the bytes message stream.
*
* @return a 64-bit integer value from the bytes message stream, interpreted as a long
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public long readLong() throws JMSException {
checkCanRead();
try {
return dataIn.readLong();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads a float
from the bytes message stream.
*
* @return a float
value from the bytes message stream
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public float readFloat() throws JMSException {
checkCanRead();
try {
return dataIn.readFloat();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads a double
from the bytes message stream.
*
* @return a double
value from the bytes message stream
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public double readDouble() throws JMSException {
checkCanRead();
try {
return dataIn.readDouble();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads a string that has been encoded using a UTF-8 format from
* the bytes message stream
*
* @return a Unicode string from the bytes message stream
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageEOFException
* If unexpected end of bytes stream has been reached.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public String readUTF() throws JMSException {
checkCanRead();
try {
return dataIn.readUTF();
} catch (EOFException e) {
throw new MessageEOFException(e.getMessage());
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Reads a byte array from the bytes message stream.
*
* If the length of array value is less than the number of bytes remaining
* to be read from the stream, the array should be filled. A subsequent call
* reads the next increment, and so on.
*
* If the number of bytes remaining in the stream is less than the length of
* array value, the bytes should be read into the array. The return value of
* the total number of bytes read will be less than the length of the array,
* indicating that there are no more bytes left to be read from the stream.
* The next read of the stream returns -1.
*
* @param value
* The buffer into which the data is read
* @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public int readBytes(byte[] value) throws JMSException {
return readBytes(value, value.length);
}
/**
* Reads a portion of the bytes message stream.
*
* If the length of array value is less than the number of bytes remaining
* to be read from the stream, the array should be filled. A subsequent call
* reads the next increment, and so on.
*
* If the number of bytes remaining in the stream is less than the length of
* array value, the bytes should be read into the array. The return value of
* the total number of bytes read will be less than the length of the array,
* indicating that there are no more bytes left to be read from the stream.
* The next read of the stream returns -1.
*
* If length is negative, then an IndexOutOfBoundsException
is
* thrown. No bytes will be read from the stream for this exception case.
*
* @param value
* The buffer into which the data is read
* @param length
* The number of bytes to read; must be less than or equal to
* value.length
* @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached
* @throws JMSException
* If the JMS provider fails to read the message due to some
* internal error.
* @throws MessageNotReadableException
* If the message is in write-only mode.
*/
@Override
public int readBytes(byte[] value, int length) throws JMSException {
if (length < 0) {
throw new IndexOutOfBoundsException("Length bytes to read can't be smaller than 0 but was " +
length);
}
checkCanRead();
try {
/**
* Almost copy of readFully implementation except that EOFException
* is not thrown if the stream is at the end of file and no byte is
* available
*/
int n = 0;
while (n < length) {
int count = dataIn.read(value, n, length - n);
if (count < 0) {
break;
}
n += count;
}
/**
* JMS specification mentions that the next read of the stream
* returns -1 if the previous read consumed the byte stream and
* there are no more bytes left to be read from the stream
*/
if (n == 0 && length > 0) {
n = -1;
}
return n;
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a boolean
to the bytes message stream
*
* @param value
* The boolean
value to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeBoolean(boolean value) throws JMSException {
checkCanWrite();
try {
dataOut.writeBoolean(value);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a byte
to the bytes message stream
*
* @param value
* The byte
value to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeByte(byte value) throws JMSException {
checkCanWrite();
try {
dataOut.writeByte(value);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a short
to the bytes message stream
*
* @param value
* The short
value to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeShort(short value) throws JMSException {
checkCanWrite();
try {
dataOut.writeShort(value);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a char
to the bytes message stream
*
* @param value
* The char
value to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeChar(char value) throws JMSException {
checkCanWrite();
try {
dataOut.writeChar(value);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a int
to the bytes message stream
*
* @param value
* The int
value to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeInt(int value) throws JMSException {
checkCanWrite();
try {
dataOut.writeInt(value);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a long
to the bytes message stream
*
* @param value
* The long
value to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeLong(long value) throws JMSException {
checkCanWrite();
try {
dataOut.writeLong(value);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a float
to the bytes message stream
*
* @param value
* The float
value to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeFloat(float value) throws JMSException {
checkCanWrite();
try {
dataOut.writeFloat(value);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a double
to the bytes message stream
*
* @param value
* The double
value to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeDouble(double value) throws JMSException {
checkCanWrite();
try {
dataOut.writeDouble(value);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a string that has been encoded using a UTF-8 format to the bytes
* message stream
*
* @param value
* The String
value to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeUTF(String value) throws JMSException {
checkCanWrite();
try {
dataOut.writeUTF(value);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a byte array to the bytes
* message stream
*
* @param value
* The byte array value to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeBytes(byte[] value) throws JMSException {
checkCanWrite();
try {
dataOut.write(value);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes a portion of a byte array to the bytes message stream.
*
* @param value
* The portion of byte array value to be written
* @param offset
* The initial offset within the byte array
* @param length
* The number of bytes to use
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
*/
@Override
public void writeBytes(byte[] value, int offset, int length) throws JMSException {
checkCanWrite();
try {
dataOut.write(value, offset, length);
} catch (IOException e) {
throw convertExceptionToJMSException(e);
}
}
/**
* Writes an object to the bytes message stream.
*
* This method works only for the boxed primitive object types
* (Integer, Double, Long ...), String objects, and byte arrays.
*
* @param value
* The Java object to be written
* @throws JMSException
* If the JMS provider fails to write the message due to some
* internal error.
* @throws MessageNotWriteableException
* If the message is in read-only mode.
* @throws MessageFormatException
* If the object is of an invalid type.
* @throws NullPointerException
* If the object is null.
*/
@Override
public void writeObject(Object value) throws JMSException {
if (value == null) {
throw new NullPointerException("Cannot write null value of object");
}
if (value instanceof Boolean) {
writeBoolean((Boolean) value);
} else if (value instanceof Character) {
writeChar((Character) value);
} else if (value instanceof Byte) {
writeByte((Byte) value);
} else if (value instanceof Short) {
writeShort((Short) value);
} else if (value instanceof Integer) {
writeInt((Integer) value);
} else if (value instanceof Long) {
writeLong((Long) value);
} else if (value instanceof Float) {
writeFloat((Float) value);
} else if (value instanceof Double) {
writeDouble((Double) value);
} else if (value instanceof String) {
writeUTF(value.toString());
} else if (value instanceof byte[]) {
writeBytes((byte[]) value);
} else {
throw new MessageFormatException("Cannot write non-primitive type: " + value.getClass());
}
}
/**
* Puts the message body in read-only mode and repositions the stream of
* bytes to the beginning.
*/
@Override
public void reset() throws JMSException {
if (dataOut != null) {
bytes = bytesOut.toByteArray();
dataOut = null;
bytesOut = null;
}
dataIn = new DataInputStream(new ByteArrayInputStream(bytes));
}
/**
* When the message is first created, and when clearBody is called, the body
* of the message is in write-only mode. After the first call to reset is
* made, the message body goes to read-only mode. when the message is sent,
* the sender can retain and modify it without affecting the sent message.
* If clearBody is called on a message, when it is in read-only mode, the
* message body is cleared and the message goes to write-only mode.
*/
@Override
public void clearBody() throws JMSException {
bytes = null;
dataIn = null;
bytesOut = new ByteArrayOutputStream();
dataOut = new DataOutputStream(bytesOut);
setBodyWritePermissions(true);
}
/**
* Reads the body of message, which can be either the body returned from the
* the receives message as bytes or the bytes put in bytesOut if it is a
* sent message.
*
* @return value The body returned as byte array
*/
public byte[] getBodyAsBytes() throws JMSException {
if (bytes != null) {
return Arrays.copyOf(bytes, bytes.length);
} else {
return bytesOut.toByteArray();
}
}
void checkCanRead() throws JMSException {
if (bytes == null) {
throw new MessageNotReadableException("Message is not readable");
}
}
void checkCanWrite() throws JMSException {
if (dataOut == null) {
throw new MessageNotWriteableException("Message is not writeable");
}
}
/*
* Unit Test Utility Function
*/
void setDataIn(DataInputStream dataIn) {
this.dataIn = dataIn;
}
void setDataOut(DataOutputStream dataOut) {
this.dataOut = dataOut;
}
}