package org.openamq.client.message;
import org.apache.commons.collections.map.ReferenceMap;
import org.apache.mina.common.ByteBuffer;
import org.openamq.AMQException;
import org.openamq.client.AMQDestination;
import org.openamq.client.AMQQueue;
import org.openamq.client.AMQTopic;
import org.openamq.framing.FieldTable;
import org.openamq.framing.BasicContentHeaderProperties;
import javax.jms.Destination;
import javax.jms.JMSException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
public abstract class AbstractJMSMessage extends AMQMessage implements javax.jms.Message
{
private static final Map _destinationCache = Collections.synchronizedMap(new ReferenceMap());
// protected Map _messageProperties;
public static final char BOOLEAN_PROPERTY_PREFIX = 'B';
public static final char BYTE_PROPERTY_PREFIX = 'b';
public static final char SHORT_PROPERTY_PREFIX = 's';
public static final char INT_PROPERTY_PREFIX = 'i';
public static final char LONG_PROPERTY_PREFIX = 'l';
public static final char FLOAT_PROPERTY_PREFIX = 'f';
public static final char DOUBLE_PROPERTY_PREFIX = 'd';
public static final char STRING_PROPERTY_PREFIX = 'S';
protected boolean _redelivered;
protected ByteBuffer _data;
protected AbstractJMSMessage(ByteBuffer data)
{
super(new BasicContentHeaderProperties());
_data = data;
if (_data != null)
{
_data.acquire();
}
}
protected AbstractJMSMessage(long deliveryTag, BasicContentHeaderProperties contentHeader, ByteBuffer data) throws AMQException
{
this(contentHeader, deliveryTag);
_data = data;
if (_data != null)
{
_data.acquire();
}
}
protected AbstractJMSMessage(BasicContentHeaderProperties contentHeader, long deliveryTag)
{
super(contentHeader, deliveryTag);
}
public String getJMSMessageID() throws JMSException
{
if (getJmsContentHeaderProperties().getMessageId() == null)
{
getJmsContentHeaderProperties().setMessageId("ID:" + _deliveryTag);
}
return getJmsContentHeaderProperties().getMessageId();
}
public void setJMSMessageID(String messageId) throws JMSException
{
getJmsContentHeaderProperties().setMessageId(messageId);
}
public long getJMSTimestamp() throws JMSException
{
return new Long(getJmsContentHeaderProperties().getTimestamp()).longValue();
}
public void setJMSTimestamp(long timestamp) throws JMSException
{
getJmsContentHeaderProperties().setTimestamp(timestamp);
}
public byte[] getJMSCorrelationIDAsBytes() throws JMSException
{
return getJmsContentHeaderProperties().getCorrelationId().getBytes();
}
public void setJMSCorrelationIDAsBytes(byte[] bytes) throws JMSException
{
getJmsContentHeaderProperties().setCorrelationId(new String(bytes));
}
public void setJMSCorrelationID(String correlationId) throws JMSException
{
getJmsContentHeaderProperties().setCorrelationId(correlationId);
}
public String getJMSCorrelationID() throws JMSException
{
return getJmsContentHeaderProperties().getCorrelationId();
}
public Destination getJMSReplyTo() throws JMSException
{
String replyToEncoding = getJmsContentHeaderProperties().getReplyTo();
if (replyToEncoding == null)
{
return null;
}
else
{
Destination dest = (Destination) _destinationCache.get(replyToEncoding);
if (dest == null)
{
char destType = replyToEncoding.charAt(0);
if (destType == 'Q')
{
dest = new AMQQueue(replyToEncoding.substring(1));
}
else if (destType == 'T')
{
dest = new AMQTopic(replyToEncoding.substring(1));
}
else
{
throw new JMSException("Illegal value in JMS_ReplyTo property: " + replyToEncoding);
}
_destinationCache.put(replyToEncoding, dest);
}
return dest;
}
}
public void setJMSReplyTo(Destination destination) throws JMSException
{
if (destination == null)
{
throw new IllegalArgumentException("Null destination not allowed");
}
if (!(destination instanceof AMQDestination))
{
throw new IllegalArgumentException("ReplyTo destination my be an AMQ destination - passed argument was type " +
destination.getClass());
}
final AMQDestination amqd = (AMQDestination) destination;
final String encodedDestination = amqd.getEncodedName();
_destinationCache.put(encodedDestination, destination);
getJmsContentHeaderProperties().setReplyTo(encodedDestination);
}
public Destination getJMSDestination() throws JMSException
{
// TODO: implement this once we have sorted out how to figure out the exchange class
return null;
}
public void setJMSDestination(Destination destination) throws JMSException
{
//To change body of implemented methods use File | Settings | File Templates.
}
public int getJMSDeliveryMode() throws JMSException
{
return getJmsContentHeaderProperties().getDeliveryMode();
}
public void setJMSDeliveryMode(int i) throws JMSException
{
getJmsContentHeaderProperties().setDeliveryMode((byte) i);
}
public boolean getJMSRedelivered() throws JMSException
{
return _redelivered;
}
public void setJMSRedelivered(boolean b) throws JMSException
{
_redelivered = b;
}
public String getJMSType() throws JMSException
{
return getMimeType();
}
public void setJMSType(String string) throws JMSException
{
throw new JMSException("Cannot set JMS Type - it is implicitly defined based on message type");
}
public long getJMSExpiration() throws JMSException
{
return new Long(getJmsContentHeaderProperties().getExpiration()).longValue();
}
public void setJMSExpiration(long l) throws JMSException
{
getJmsContentHeaderProperties().setExpiration(l);
}
public int getJMSPriority() throws JMSException
{
return getJmsContentHeaderProperties().getPriority();
}
public void setJMSPriority(int i) throws JMSException
{
getJmsContentHeaderProperties().setPriority((byte)i);
}
public void clearProperties() throws JMSException
{
if (getJmsContentHeaderProperties().getHeaders() != null)
{
getJmsContentHeaderProperties().getHeaders().clear();
}
}
public boolean propertyExists(String propertyName) throws JMSException
{
checkPropertyName(propertyName);
if (getJmsContentHeaderProperties().getHeaders() == null)
{
return false;
}
else
{
// TODO: fix this
return getJmsContentHeaderProperties().getHeaders().containsKey(STRING_PROPERTY_PREFIX + propertyName);
}
}
public boolean getBooleanProperty(String propertyName) throws JMSException
{
checkPropertyName(propertyName);
if (getJmsContentHeaderProperties().getHeaders() == null)
{
return Boolean.valueOf(null).booleanValue();
}
else
{
// store as integer as temporary workaround
//Boolean b = (Boolean) getJmsContentHeaderProperties().headers.get(BOOLEAN_PROPERTY_PREFIX + propertyName);
Long b = (Long) getJmsContentHeaderProperties().getHeaders().get(BOOLEAN_PROPERTY_PREFIX + propertyName);
if (b == null)
{
return Boolean.valueOf(null).booleanValue();
}
else
{
return b.longValue() != 0;
}
}
}
public byte getByteProperty(String propertyName) throws JMSException
{
checkPropertyName(propertyName);
if (getJmsContentHeaderProperties().getHeaders() == null)
{
return Byte.valueOf(null).byteValue();
}
else
{
Byte b = (Byte) getJmsContentHeaderProperties().getHeaders().get(BYTE_PROPERTY_PREFIX + propertyName);
if (b == null)
{
return Byte.valueOf(null).byteValue();
}
else
{
return b.byteValue();
}
}
}
public short getShortProperty(String propertyName) throws JMSException
{
checkPropertyName(propertyName);
if (getJmsContentHeaderProperties().getHeaders() == null)
{
return Short.valueOf(null).shortValue();
}
else
{
Short s = (Short) getJmsContentHeaderProperties().getHeaders().get(SHORT_PROPERTY_PREFIX + propertyName);
if (s == null)
{
return Short.valueOf(null).shortValue();
}
else
{
return s.shortValue();
}
}
}
public int getIntProperty(String propertyName) throws JMSException
{
checkPropertyName(propertyName);
if (getJmsContentHeaderProperties().getHeaders() == null)
{
return Integer.valueOf(null).intValue();
}
else
{
Integer i = (Integer) getJmsContentHeaderProperties().getHeaders().get(INT_PROPERTY_PREFIX + propertyName);
if (i == null)
{
return Integer.valueOf(null).intValue();
}
else
{
return i.intValue();
}
}
}
public long getLongProperty(String propertyName) throws JMSException
{
checkPropertyName(propertyName);
if (getJmsContentHeaderProperties().getHeaders() == null)
{
return Long.valueOf(null).longValue();
}
else
{
Long l = (Long) getJmsContentHeaderProperties().getHeaders().get(LONG_PROPERTY_PREFIX + propertyName);
if (l == null)
{
// temp - the spec says do this but this throws a NumberFormatException
//return Long.valueOf(null).longValue();
return 0;
}
else
{
return l.longValue();
}
}
}
public float getFloatProperty(String propertyName) throws JMSException
{
checkPropertyName(propertyName);
if (getJmsContentHeaderProperties().getHeaders() == null)
{
return Float.valueOf(null).floatValue();
}
else
{
final Float f = (Float) getJmsContentHeaderProperties().getHeaders().get(FLOAT_PROPERTY_PREFIX + propertyName);
if (f == null)
{
return Float.valueOf(null).floatValue();
}
else
{
return f.floatValue();
}
}
}
public double getDoubleProperty(String propertyName) throws JMSException
{
checkPropertyName(propertyName);
if (getJmsContentHeaderProperties().getHeaders() == null)
{
return Double.valueOf(null).doubleValue();
}
else
{
final Double d = (Double) getJmsContentHeaderProperties().getHeaders().get(DOUBLE_PROPERTY_PREFIX + propertyName);
if (d == null)
{
return Double.valueOf(null).doubleValue();
}
else
{
return d.shortValue();
}
}
}
public String getStringProperty(String propertyName) throws JMSException
{
checkPropertyName(propertyName);
if (getJmsContentHeaderProperties().getHeaders() == null)
{
return null;
}
else
{
return (String) getJmsContentHeaderProperties().getHeaders().get(STRING_PROPERTY_PREFIX + propertyName);
}
}
public Object getObjectProperty(String propertyName) throws JMSException
{
checkPropertyName(propertyName);
throw new JMSException("Not implemented yet");
}
public Enumeration getPropertyNames() throws JMSException
{
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public void setBooleanProperty(String propertyName, boolean b) throws JMSException
{
checkPropertyName(propertyName);
//getJmsContentHeaderProperties().headers.put(BOOLEAN_PROPERTY_PREFIX + propertyName, Boolean.valueOf(b));
getJmsContentHeaderProperties().getHeaders().put(BOOLEAN_PROPERTY_PREFIX + propertyName, b?new Long(1):new Long(0));
}
public void setByteProperty(String propertyName, byte b) throws JMSException
{
checkPropertyName(propertyName);
getJmsContentHeaderProperties().getHeaders().put(BYTE_PROPERTY_PREFIX + propertyName, new Byte(b));
}
public void setShortProperty(String propertyName, short i) throws JMSException
{
checkPropertyName(propertyName);
getJmsContentHeaderProperties().getHeaders().put(SHORT_PROPERTY_PREFIX + propertyName, new Short(i));
}
public void setIntProperty(String propertyName, int i) throws JMSException
{
checkPropertyName(propertyName);
getJmsContentHeaderProperties().getHeaders().put(INT_PROPERTY_PREFIX + propertyName, new Integer(i));
}
public void setLongProperty(String propertyName, long l) throws JMSException
{
checkPropertyName(propertyName);
getJmsContentHeaderProperties().getHeaders().put(LONG_PROPERTY_PREFIX + propertyName, new Long(l));
}
public void setFloatProperty(String propertyName, float f) throws JMSException
{
checkPropertyName(propertyName);
getJmsContentHeaderProperties().getHeaders().put(FLOAT_PROPERTY_PREFIX + propertyName, new Float(f));
}
public void setDoubleProperty(String propertyName, double v) throws JMSException
{
checkPropertyName(propertyName);
getJmsContentHeaderProperties().getHeaders().put(DOUBLE_PROPERTY_PREFIX + propertyName, new Double(v));
}
public void setStringProperty(String propertyName, String value) throws JMSException
{
checkPropertyName(propertyName);
createPropertyMapIfRequired();
propertyName = STRING_PROPERTY_PREFIX + propertyName;
getJmsContentHeaderProperties().getHeaders().put(propertyName, value);
}
private void createPropertyMapIfRequired()
{
if (getJmsContentHeaderProperties().getHeaders() == null)
{
getJmsContentHeaderProperties().setHeaders(new FieldTable());
}
}
public void setObjectProperty(String string, Object object) throws JMSException
{
//To change body of implemented methods use File | Settings | File Templates.
}
public void acknowledge() throws JMSException
{
// the JMS 1.1 spec says in section 3.6 that calls to acknowledge are ignored when client acknowledge
// is not specified. In our case, we only set the session field where client acknowledge mode is specified.
if (_session != null)
{
// we set multiple to true here since acknowledgement implies acknowledge of all previous messages
// received on the session
_session.acknowledgeMessage(_deliveryTag, true);
}
}
public abstract void clearBody() throws JMSException;
/**
* Get a String representation of the body of the message. Used in the
* toString() method which outputs this before message properties.
*/
public abstract String toBodyString() throws JMSException;
public abstract String getMimeType();
public String toString()
{
try
{
StringBuffer buf = new StringBuffer("Body:\n");
buf.append(toBodyString());
buf.append("\nJMS timestamp: ").append(getJMSTimestamp());
buf.append("\nJMS expiration: ").append(getJMSExpiration());
buf.append("\nJMS priority: ").append(getJMSPriority());
buf.append("\nJMS delivery mode: ").append(getJMSDeliveryMode());
buf.append("\nJMS reply to: ").append(String.valueOf(getJMSReplyTo()));
buf.append("\nAMQ message number: ").append(_deliveryTag);
buf.append("\nProperties:");
if (getJmsContentHeaderProperties().getHeaders() == null)
{
buf.append("<NONE>");
}
else
{
final Iterator it = getJmsContentHeaderProperties().getHeaders().entrySet().iterator();
while (it.hasNext())
{
final Map.Entry entry = (Map.Entry) it.next();
final String propertyName = (String) entry.getKey();
if (propertyName == null)
{
buf.append("\nInternal error: Property with NULL key defined");
}
else
{
buf.append('\n').append(propertyName.substring(1));
char typeIdentifier = propertyName.charAt(0);
switch (typeIdentifier)
{
case org.openamq.client.message.AbstractJMSMessage.BOOLEAN_PROPERTY_PREFIX:
buf.append("<boolean> ");
break;
case org.openamq.client.message.AbstractJMSMessage.BYTE_PROPERTY_PREFIX:
buf.append("<byte> ");
break;
case org.openamq.client.message.AbstractJMSMessage.SHORT_PROPERTY_PREFIX:
buf.append("<short> ");
break;
case org.openamq.client.message.AbstractJMSMessage.INT_PROPERTY_PREFIX:
buf.append("<int> ");
break;
case org.openamq.client.message.AbstractJMSMessage.LONG_PROPERTY_PREFIX:
buf.append("<long> ");
break;
case org.openamq.client.message.AbstractJMSMessage.FLOAT_PROPERTY_PREFIX:
buf.append("<float> ");
break;
case org.openamq.client.message.AbstractJMSMessage.DOUBLE_PROPERTY_PREFIX:
buf.append("<double> ");
break;
case org.openamq.client.message.AbstractJMSMessage.STRING_PROPERTY_PREFIX:
buf.append("<string> ");
break;
default:
buf.append("<unknown type (identifier " +
typeIdentifier + ") ");
}
buf.append(String.valueOf(entry.getValue()));
}
}
}
return buf.toString();
}
catch (JMSException e)
{
return e.toString();
}
}
public Map getUnderlyingMessagePropertiesMap()
{
return getJmsContentHeaderProperties().getHeaders();
}
public void setUnderlyingMessagePropertiesMap(FieldTable messageProperties)
{
getJmsContentHeaderProperties().setHeaders(messageProperties);
}
private void checkPropertyName(String propertyName)
{
if (propertyName == null)
{
throw new IllegalArgumentException("Property name must not be null");
}
else if ("".equals(propertyName))
{
throw new IllegalArgumentException("Property name must not be the empty string");
}
if (getJmsContentHeaderProperties().getHeaders() == null)
{
getJmsContentHeaderProperties().setHeaders(new FieldTable());
}
}
public FieldTable populateHeadersFromMessageProperties()
{
if (getJmsContentHeaderProperties().getHeaders() == null)
{
return null;
}
else
{
//
// We need to convert every property into a String representation
// Note that type information is preserved in the property name
//
final FieldTable table = new FieldTable();
final Iterator entries = getJmsContentHeaderProperties().getHeaders().entrySet().iterator();
while (entries.hasNext())
{
final Map.Entry entry = (Map.Entry) entries.next();
final String propertyName = (String) entry.getKey();
if (propertyName == null)
{
continue;
}
else
{
table.put(propertyName, entry.getValue().toString());
}
}
return table;
}
}
public BasicContentHeaderProperties getJmsContentHeaderProperties()
{
return (BasicContentHeaderProperties) _contentHeaderProperties;
}
public ByteBuffer getData()
{
// make sure we rewind the data just in case any method has moved the
// position beyond the start
if (_data != null)
{
_data.rewind();
}
return _data;
}
}