package org.openamq.client.message;
import org.openamq.framing.BasicContentHeaderProperties;
import org.openamq.framing.ContentHeaderBody;
import org.openamq.AMQException;
import org.apache.mina.common.ByteBuffer;
import javax.jms.JMSException;
import javax.jms.MessageNotReadableException;
import javax.jms.MessageNotWriteableException;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.CharacterCodingException;
public class JMSBytesMessage extends AbstractJMSMessage implements javax.jms.BytesMessage
{
private static final String MIME_TYPE = "application/octet-stream";
private boolean _readable = false;
/**
* The default initial size of the buffer. The buffer expands automatically.
*/
private static final int DEFAULT_BUFFER_INITIAL_SIZE = 1024;
JMSBytesMessage()
{
this(null);
}
/**
* Construct a bytes message with existing data.
* @param data the data that comprises this message. If data is null, you get a 1024 byte buffer that is
* set to auto expand
*/
JMSBytesMessage(ByteBuffer data)
{
super(data); // this instanties a content header
getJmsContentHeaderProperties().setContentType(MIME_TYPE);
if (_data == null)
{
_data = ByteBuffer.allocate(DEFAULT_BUFFER_INITIAL_SIZE);
_data.setAutoExpand(true);
}
_readable = (data != null);
}
JMSBytesMessage(long messageNbr, ByteBuffer data, ContentHeaderBody contentHeader)
throws AMQException
{
// TODO: this casting is ugly. Need to review whole ContentHeaderBody idea
super(messageNbr, (BasicContentHeaderProperties) contentHeader.properties, data);
getJmsContentHeaderProperties().setContentType(MIME_TYPE);
_readable = true;
}
public void clearBody() throws JMSException
{
_data.clear();
_readable = false;
}
public String toBodyString() throws JMSException
{
checkReadable();
try
{
return getText();
}
catch (IOException e)
{
throw new JMSException(e.toString());
}
}
/**
* We reset the stream before and after reading the data. This means that toString() will always output
* the entire message and also that the caller can then immediately start reading as if toString() had
* never been called.
* @return
* @throws IOException
*/
private String getText() throws IOException
{
// this will use the default platform encoding
if (_data == null)
{
return null;
}
int pos = _data.position();
_data.rewind();
// one byte left is for the end of frame marker
if (_data.remaining() == 0)
{
// this is really redundant since pos must be zero
_data.position(pos);
return null;
}
else
{
String data = _data.getString(Charset.forName("UTF8").newDecoder());
_data.position(pos);
return data;
}
}
public String getMimeType()
{
return MIME_TYPE;
}
public long getBodyLength() throws JMSException
{
checkReadable();
return _data.limit();
}
private void checkReadable() throws MessageNotReadableException
{
if (!_readable)
{
throw new MessageNotReadableException("You need to call reset() to make the message readable");
}
}
private void checkWritable() throws MessageNotWriteableException
{
if (_readable)
{
throw new MessageNotWriteableException("You need to call clearBody() to make the message writable");
}
}
public boolean readBoolean() throws JMSException
{
checkReadable();
return _data.get() != 0;
}
public byte readByte() throws JMSException
{
checkReadable();
return _data.get();
}
public int readUnsignedByte() throws JMSException
{
checkReadable();
return _data.getUnsigned();
}
public short readShort() throws JMSException
{
checkReadable();
return _data.getShort();
}
public int readUnsignedShort() throws JMSException
{
checkReadable();
return _data.getUnsignedShort();
}
public char readChar() throws JMSException
{
checkReadable();
return _data.getChar();
}
public int readInt() throws JMSException
{
checkReadable();
return _data.getInt();
}
public long readLong() throws JMSException
{
checkReadable();
return _data.getLong();
}
public float readFloat() throws JMSException
{
checkReadable();
return _data.getFloat();
}
public double readDouble() throws JMSException
{
checkReadable();
return _data.getDouble();
}
public String readUTF() throws JMSException
{
checkReadable();
try
{
return _data.getString(Charset.forName("UTF-8").newDecoder());
}
catch (CharacterCodingException e)
{
JMSException je = new JMSException("Error decoding byte stream as a UTF8 string: " + e);
je.setLinkedException(e);
throw je;
}
}
public int readBytes(byte[] bytes) throws JMSException
{
if (bytes == null)
{
throw new IllegalArgumentException("byte array must not be null");
}
checkReadable();
int count = (_data.remaining() >= bytes.length ? bytes.length : _data.remaining());
_data.get(bytes, 0, count);
return count;
}
public int readBytes(byte[] bytes, int maxLength) throws JMSException
{
if (bytes == null)
{
throw new IllegalArgumentException("byte array must not be null");
}
if (maxLength > bytes.length)
{
throw new IllegalArgumentException("maxLength must be <= bytes.length");
}
checkReadable();
int count = (_data.remaining() >= maxLength ? maxLength : _data.remaining());
_data.get(bytes, 0, count);
return count;
}
public void writeBoolean(boolean b) throws JMSException
{
checkWritable();
_data.put(b?(byte)1:(byte)0);
}
public void writeByte(byte b) throws JMSException
{
checkWritable();
_data.put(b);
}
public void writeShort(short i) throws JMSException
{
checkWritable();
_data.putShort(i);
}
public void writeChar(char c) throws JMSException
{
checkWritable();
_data.putChar(c);
}
public void writeInt(int i) throws JMSException
{
checkWritable();
_data.putInt(i);
}
public void writeLong(long l) throws JMSException
{
checkWritable();
_data.putLong(l);
}
public void writeFloat(float v) throws JMSException
{
checkWritable();
_data.putFloat(v);
}
public void writeDouble(double v) throws JMSException
{
checkWritable();
_data.putDouble(v);
}
public void writeUTF(String string) throws JMSException
{
checkWritable();
try
{
_data.putString(string, Charset.forName("UTF-8").newEncoder());
}
catch (CharacterCodingException e)
{
JMSException ex = new JMSException("Unable to encode string: " + e);
ex.setLinkedException(e);
throw ex;
}
}
public void writeBytes(byte[] bytes) throws JMSException
{
checkWritable();
_data.put(bytes);
}
public void writeBytes(byte[] bytes, int offset, int length) throws JMSException
{
checkWritable();
_data.put(bytes, offset, length);
}
public void writeObject(Object object) throws JMSException
{
checkWritable();
if (object == null)
{
throw new NullPointerException("Argument must not be null");
}
_data.putObject(object);
}
public void reset() throws JMSException
{
checkWritable();
_data.flip();
_readable = true;
}
public boolean isReadable()
{
return _readable;
}
}