/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.jms.message; import com.caucho.jms.connection.JmsSession; import com.caucho.hessian.io.*; import com.caucho.vfs.*; import com.caucho.util.*; import javax.jms.*; import java.lang.ref.WeakReference; import java.io.*; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; /** * A basic message. */ public class MessageImpl implements Message, java.io.Serializable { protected static final Logger log = Logger.getLogger(MessageImpl.class.getName()); protected static final L10N L = new L10N(MessageImpl.class); private static final HashSet<String> _reserved; private transient volatile WeakReference<JmsSession> _sessionRef; private String _messageId; private String _correlationId; private long _timestamp; private long _expiration; //XXX: private transient Destination _destination; private transient Destination _replyTo; private int _deliveryMode = DeliveryMode.PERSISTENT; private boolean _isRedelivered; private String _messageType; private int _priority = 4; private long _sequence; private HashMap<String,Object> _properties; private transient boolean _isHeaderWriteable = true; private transient boolean _isBodyWriteable = true; public MessageImpl() { } /** * Create a message, copying the properties */ public MessageImpl(Message msg) throws JMSException { _messageId = msg.getJMSMessageID(); _correlationId = msg.getJMSCorrelationID(); _timestamp = msg.getJMSTimestamp(); _expiration = msg.getJMSExpiration(); _destination = msg.getJMSDestination(); _replyTo = msg.getJMSReplyTo(); _deliveryMode = msg.getJMSDeliveryMode(); _isRedelivered = msg.getJMSRedelivered(); _messageType = msg.getJMSType(); _priority = msg.getJMSPriority(); Enumeration e = msg.getPropertyNames(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); setObjectProperty(name, msg.getObjectProperty(name)); } _isHeaderWriteable = true; _isBodyWriteable = true; } public MessageImpl(MessageImpl msg) { if (msg._properties != null) { _properties = new HashMap<String,Object>(msg._properties); } _messageId = msg._messageId; _correlationId = msg._correlationId; _timestamp = msg._timestamp; _expiration = msg._expiration; _destination = msg._destination; _replyTo = msg._replyTo; _deliveryMode = msg._deliveryMode; _isRedelivered = msg._isRedelivered; _messageType = msg._messageType; _priority = msg._priority; _isHeaderWriteable = false; _isBodyWriteable = false; } /** * Sets the session. */ public void setSession(JmsSession session) { _sessionRef = new WeakReference<JmsSession>(session); } /** * Returns the type enumeration. */ public MessageType getType() { return MessageType.NULL; } /** * Returns the message id. */ public String getJMSMessageID() { return _messageId; } /** * Sets the message id. * * @param id the new message id */ public void setJMSMessageID(String id) { _messageId = id; } /** * Returns the time the message was sent. */ public long getJMSTimestamp() throws JMSException { return _timestamp; } /** * Sets the time the message was sent. * * @param time the message timestamp */ public void setJMSTimestamp(long time) throws JMSException { _timestamp = time; } /** * Returns the correlation id. */ public byte []getJMSCorrelationIDAsBytes() throws JMSException { try { if (_correlationId == null) return null; else return _correlationId.getBytes("UTF8"); } catch (Throwable e) { log.log(Level.WARNING, e.toString(), e); return null; } } /** * Sets the correlation id. * * @param id the correlation id */ public void setJMSCorrelationIDAsBytes(byte []id) throws JMSException { try { _correlationId = new String(id, 0, id.length, "UTF8"); } catch (Exception e) { log.log(Level.WARNING, e.toString(), e); } } /** * Returns the correlation id. */ public String getJMSCorrelationID() throws JMSException { return _correlationId; } /** * Sets the correlation id. * * @param id the correlation id */ public void setJMSCorrelationID(String id) throws JMSException { _correlationId = id; } /** * Gets the reply-to destination */ public Destination getJMSReplyTo() throws JMSException { return _replyTo; } /** * Sets the reply-to destination * * @param replyTo the destination */ public void setJMSReplyTo(Destination replyTo) throws JMSException { _replyTo = replyTo; } /** * Gets the destination */ public Destination getJMSDestination() throws JMSException { return _destination; } /** * Sets the reply-to destination * * @param destination the destination */ public void setJMSDestination(Destination destination) throws JMSException { _destination = destination; } /** * Gets the delivery model */ public int getJMSDeliveryMode() throws JMSException { return _deliveryMode; } /** * Sets the delivery mode * * @param deliveryMode the delivery mode */ public void setJMSDeliveryMode(int deliveryMode) throws JMSException { _deliveryMode = deliveryMode; } /** * Returns if the message is being redelivered. */ public boolean getJMSRedelivered() { return _isRedelivered; } /** * Sets if the message is being redelivered. * * @param deliveryMode the delivery mode */ public void setJMSRedelivered(boolean isRedelivered) { _isRedelivered = isRedelivered; } /** * Returns the message type */ public String getJMSType() throws JMSException { return _messageType; } /** * Sets the message type. * * @param type the delivery mode */ public void setJMSType(String type) throws JMSException { _messageType = type; } /** * Returns the message expiration time. */ public long getJMSExpiration() throws JMSException { return _expiration; } /** * Sets the message expiration type. * * @param time the expiration time */ public void setJMSExpiration(long time) throws JMSException { _expiration = time; } /** * Returns the message priority. */ public int getJMSPriority() { return _priority; } /** * Sets the message priority. * * @param priority the priority */ public void setJMSPriority(int priority) { _priority = priority; } /** * Clears the message properties, making them writeable. */ public void clearProperties() throws JMSException { if (_properties != null) _properties.clear(); _isHeaderWriteable = true; } /** * Returns true if the property exists. */ public boolean propertyExists(String name) throws JMSException { if (_properties == null) return false; return _properties.keySet().contains(name); } /** * Returns a boolean property with the given name. */ @Override public boolean getBooleanProperty(String name) throws JMSException { // jms/214f - TCK Object value = getObjectProperty(name); if (value != null) return ObjectConverter.toBoolean(value); else return false; } /** * Returns a property as a byte */ public byte getByteProperty(String name) throws JMSException { return ObjectConverter.toByte(getObjectProperty(name)); } /** * Returns a property as a short */ public short getShortProperty(String name) throws JMSException { return ObjectConverter.toShort(getObjectProperty(name)); } /** * Returns a property as an integer */ public int getIntProperty(String name) throws JMSException { return ObjectConverter.toInt(getObjectProperty(name)); } /** * Returns a property as a long */ public long getLongProperty(String name) throws JMSException { return ObjectConverter.toLong(getObjectProperty(name)); } /** * Returns a property as a float */ public float getFloatProperty(String name) throws JMSException { return ObjectConverter.toFloat(getObjectProperty(name)); } /** * Returns a property as a double */ public double getDoubleProperty(String name) throws JMSException { return ObjectConverter.toDouble(getObjectProperty(name)); } /** * Returns a string property. */ public String getStringProperty(String name) throws JMSException { Object prop = getObjectProperty(name); if (prop == null) return null; return String.valueOf(prop); } /** * Returns a string property. */ public Object getObjectProperty(String name) throws JMSException { if (_properties == null || name == null) return null; else return _properties.get(name); } /** * Returns an enumeration of the message's properties. */ public Enumeration getPropertyNames() throws JMSException { if (_properties == null) return NullEnumeration.create(); else return Collections.enumeration(_properties.keySet()); } /** * Sets a boolean property. * * @param name the property name * @param value the property's value */ public void setBooleanProperty(String name, boolean value) throws JMSException { setObjectProperty(name, new Boolean(value)); } /** * Sets a byte property. * * @param name the property name * @param value the property's value */ public void setByteProperty(String name, byte value) throws JMSException { setObjectProperty(name, new Byte(value)); } /** * Sets a short property. * * @param name the property name * @param value the property's value */ public void setShortProperty(String name, short value) throws JMSException { setObjectProperty(name, new Short(value)); } /** * Sets an integer property. * * @param name the property name * @param value the property's value */ public void setIntProperty(String name, int value) throws JMSException { setObjectProperty(name, new Integer(value)); } /** * Sets a long property. * * @param name the property name * @param value the property's value */ public void setLongProperty(String name, long value) throws JMSException { setObjectProperty(name, new Long(value)); } /** * Sets a float property. * * @param name the property name * @param value the property's value */ public void setFloatProperty(String name, float value) throws JMSException { setObjectProperty(name, new Float(value)); } /** * Sets a double property. * * @param name the property name * @param value the property's value */ public void setDoubleProperty(String name, double value) throws JMSException { setObjectProperty(name, new Double(value)); } /** * Sets a string property. * * @param name the property name * @param value the property's value */ public void setStringProperty(String name, String value) throws JMSException { setObjectProperty(name, value); } /** * Sets an object property. * * @param name the property name * @param value the property's value */ public void setObjectProperty(String name, Object value) throws JMSException { checkPropertyWriteable(); if (name == null) throw new NullPointerException(); else if ("".equals(name)) throw new IllegalArgumentException(); if (isReserved(name)) throw new JMSException(L.l("'{0}' is a reserved property name.", name)); if (! (value == null || value instanceof Number || value instanceof String || value instanceof Boolean)) throw new MessageFormatException(L.l("{0} is an illegal object property value", value.getClass().getName())); if (_properties == null) _properties = new HashMap<String,Object>(); _properties.put(name, value); } /** * Acknowledge receipt of this message. */ public void acknowledge() throws JMSException { WeakReference<JmsSession> sessionRef = _sessionRef; _sessionRef = null; JmsSession session; if (sessionRef != null && (session = sessionRef.get()) != null) { session.acknowledge(); } } /** * Clears the body, setting write mode. */ public void clearBody() throws JMSException { _isBodyWriteable = true; } /** * Sets the body for reading. */ public void setReceive() throws JMSException { _isHeaderWriteable = false; _isBodyWriteable = false; } /** * Sets the body for reading. */ protected void setBodyReadOnly() { _isBodyWriteable = false; } /** * Returns the properties. */ public HashMap<String,Object> getProperties() { return _properties; } public long getSequence() { return _sequence; } public void setSequence(long seq) { _sequence = seq; } public MessageImpl copy() { MessageImpl msg = new MessageImpl(); copy(msg); return msg; } /** * Serialize the properties to an input stream. */ public InputStream propertiesToInputStream() throws IOException { if (_properties == null || _properties.size() == 0) return null; TempOutputStream out = new TempOutputStream(); writeProperties(out); out.close(); return out.openRead(); } /** * Serialize the properties to an input stream. */ public void writeProperties(OutputStream os) throws IOException { if (_properties == null || _properties.size() == 0) return; Hessian2Output out = new Hessian2Output(os); out.writeString(_messageId); out.writeBoolean(_isRedelivered); out.writeInt(_priority); out.writeLong(_timestamp); out.writeInt(_deliveryMode); if (_destination instanceof java.io.Serializable) out.writeObject(_destination); else out.writeObject(null); if (_replyTo instanceof java.io.Serializable) out.writeObject(_replyTo); else out.writeObject(null); for (Map.Entry<String,Object> entry : _properties.entrySet()) { out.writeString(entry.getKey()); out.writeObject(entry.getValue()); } out.close(); } /** * Read the properties from an input stream. */ public void readProperties(InputStream is) throws IOException, JMSException { if (is == null) return; Hessian2Input in = new Hessian2Input(is); _messageId = in.readString(); _isRedelivered = in.readBoolean(); _priority = in.readInt(); _timestamp = in.readLong(); _deliveryMode = in.readInt(); _destination = (Destination) in.readObject(); _replyTo = (Destination) in.readObject(); while (! in.isEnd()) { String key = in.readString(); Object value = in.readObject(); setObjectProperty(key, value); } in.close(); } /** * Serialize the body to an input stream. */ public InputStream bodyToInputStream() throws IOException { return null; } /** * Serialize the body to an output stream. */ public void writeBody(OutputStream os) throws IOException { } /** * Read the body from an input stream. */ public void readBody(InputStream is) throws IOException, JMSException { } protected void checkHeaderWriteable() throws JMSException { if (! _isHeaderWriteable) throw new MessageNotWriteableException(L.l("received messages can't be written.")); } protected void checkPropertyWriteable() throws JMSException { if (! _isHeaderWriteable) throw new MessageNotWriteableException(L.l("properties for received messages are read-only.")); } protected void checkBodyWriteable() throws JMSException { if (! _isBodyWriteable) throw new MessageNotWriteableException(L.l("received messages can't be written.")); } protected void checkBodyReadable() throws JMSException { if (_isBodyWriteable) throw new MessageNotReadableException(L.l("write-only messages can't be read until reset() is called.")); } protected void copy(MessageImpl newMsg) { if (_properties != null) { newMsg._properties = new HashMap<String,Object>(_properties); } newMsg._messageId = _messageId; newMsg._correlationId = _correlationId; newMsg._timestamp = _timestamp; newMsg._expiration = _expiration; newMsg._destination = _destination; newMsg._replyTo = _replyTo; newMsg._deliveryMode = _deliveryMode; newMsg._isRedelivered = _isRedelivered; newMsg._messageType = _messageType; newMsg._priority = _priority; } public String toString() { if (_messageId != null) return getClass().getSimpleName() + "[" + _messageId + "]"; else if (Alarm.isTest()) return getClass().getSimpleName() + "[]"; else return getClass().getSimpleName() + "@" + System.identityHashCode(this); } public static boolean isReserved(String name) { return _reserved.contains(name.toUpperCase(Locale.ENGLISH)); } static { _reserved = new HashSet<String>(); _reserved.add("TRUE"); _reserved.add("FALSE"); _reserved.add("NULL"); _reserved.add("NOT"); _reserved.add("AND"); _reserved.add("OR"); _reserved.add("BETWEEN"); _reserved.add("LIKE"); _reserved.add("IN"); _reserved.add("IS"); _reserved.add("ESCAPE"); } }