View Javadoc

    1   /***
    2    *
    3    * Copyright 2004 Protique Ltd
    4    *
    5    * Licensed under the Apache License, Version 2.0 (the "License");
    6    * you may not use this file except in compliance with the License.
    7    * You may obtain a copy of the License at
    8    *
    9    * http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   **/
    18  package org.codehaus.activemq.message;
    19
    20  import javax.jms.JMSException;
    21  import javax.jms.MapMessage;
    22  import javax.jms.MessageFormatException;
    23  import javax.jms.MessageNotWriteableException;
    24  import java.io.DataInput;
    25  import java.io.DataOutput;
    26  import java.io.IOException;
    27  import java.util.Enumeration;
    28  import java.util.Hashtable;
    29
    30  /***
    31   * A <CODE>MapMessage</CODE> object is used to send a set of name-value pairs. The names are <CODE>String</CODE>
    32   * objects, and the values are primitive data types in the Java programming language. The names must have a value that
    33   * is not null, and not an empty string. The entries can be accessed sequentially or randomly by name. The order of the
    34   * entries is undefined. <CODE>MapMessage</CODE> inherits from the <CODE>Message</CODE> interface and adds a
    35   * message body that contains a Map.
    36   * <P>
    37   * The primitive types can be read or written explicitly using methods for each type. They may also be read or written
    38   * generically as objects. For instance, a call to <CODE>MapMessage.setInt("foo", 6)</CODE> is equivalent to <CODE>
    39   * MapMessage.setObject("foo", new Integer(6))</CODE>. Both forms are provided, because the explicit form is
    40   * convenient for static programming, and the object form is needed when types are not known at compile time.
    41   * <P>
    42   * When a client receives a <CODE>MapMessage</CODE>, it is in read-only mode. If a client attempts to write to the
    43   * message at this point, a <CODE>MessageNotWriteableException</CODE> is thrown. If <CODE>clearBody</CODE> is
    44   * called, the message can now be both read from and written to.
    45   * <P>
    46   * <CODE>MapMessage</CODE> objects support the following conversion table. The marked cases must be supported. The
    47   * unmarked cases must throw a <CODE>JMSException</CODE>. The <CODE>String</CODE> -to-primitive conversions may
    48   * throw a runtime exception if the primitive's <CODE>valueOf()</CODE> method does not accept it as a valid <CODE>
    49   * String</CODE> representation of the primitive.
    50   * <P>
    51   * A value written as the row type can be read as the column type.
    52   * <p/>
    53   * <PRE>| | boolean byte short char int long float double String byte[]
    54   * |---------------------------------------------------------------------- |boolean | X X |byte | X X X X X |short | X
    55   * X X X |char | X X |int | X X X |long | X X |float | X X X |double | X X |String | X X X X X X X X |byte[] | X
    56   * |----------------------------------------------------------------------
    57   * <p/>
    58   * </PRE>
    59   * <p/>
    60   * <P>
    61   * Attempting to read a null value as a primitive type must be treated as calling the primitive's corresponding <code>valueOf(String)</code>
    62   * conversion method with a null value. Since <code>char</code> does not support a <code>String</code> conversion,
    63   * attempting to read a null value as a <code>char</code> must throw a <code>NullPointerException</code>.
    64   *
    65   * @see javax.jms.Session#createMapMessage()
    66   * @see javax.jms.BytesMessage
    67   * @see javax.jms.Message
    68   * @see javax.jms.ObjectMessage
    69   * @see javax.jms.StreamMessage
    70   * @see javax.jms.TextMessage
    71   */
    72  public class ActiveMQMapMessage extends ActiveMQMessage implements MapMessage {
    73      private Hashtable theTable;
    74
    75      /***
    76       * Return the type of Packet
    77       *
    78       * @return integer representation of the type of Packet
    79       */
    80      public int getPacketType() {
    81          return ACTIVEMQ_MAP_MESSAGE;
    82      }
    83
    84      /***
    85       * @return Returns a shallow copy of the message instance
    86       * @throws JMSException
    87       */
    88      public ActiveMQMessage shallowCopy() throws JMSException {
    89          ActiveMQMapMessage other = new ActiveMQMapMessage();
    90          this.initializeOther(other);
    91          other.theTable = this.theTable;
    92          return other;
    93      }
    94
    95      /***
    96       * @return Returns a deep copy of the message - note the header fields are only shallow copied
    97       * @throws JMSException
    98       */
    99      public ActiveMQMessage deepCopy() throws JMSException {
    100         ActiveMQMapMessage other = new ActiveMQMapMessage();
    101         this.initializeOther(other);
    102         if (this.theTable != null) {
    103             other.theTable = (Hashtable) this.theTable.clone();
    104         }
    105         return other;
    106     }
    107
    108     /***
    109      * set the table body
    110      *
    111      * @param newTable the new data to set
    112      */
    113     public void setTable(Hashtable newTable) {
    114         theTable = newTable;
    115     }
    116
    117     /***
    118      * @return Returns the table body
    119      * @throws JMSException
    120      */
    121     public Hashtable getTable() throws JMSException {
    122         if (theTable == null) {
    123             try {
    124                 super.buildBodyFromBytes();
    125             }
    126             catch (IOException ioe) {
    127                 JMSException jmsEx = new JMSException("building table from data failed");
    128                 jmsEx.setLinkedException(ioe);
    129                 throw jmsEx;
    130             }
    131         }
    132         if (theTable == null) {
    133             theTable = new Hashtable();
    134         }
    135         return theTable;
    136     }
    137
    138     /***
    139      * Clears out the message body. Clearing a message's body does not clear its header values or property entries.
    140      * <P>
    141      * If this message body was read-only, calling this method leaves the message body in the same state as an empty
    142      * body in a newly created message.
    143      *
    144      * @throws JMSException if the JMS provider fails to clear the message body due to some internal error.
    145      */
    146     public void clearBody() throws JMSException {
    147         super.clearBody();
    148         getTable().clear();
    149     }
    150
    151     /***
    152      * Returns the <CODE>boolean</CODE> value with the specified name.
    153      *
    154      * @param name the name of the <CODE>boolean</CODE>
    155      * @return the <CODE>boolean</CODE> value with the specified name
    156      * @throws JMSException           if the JMS provider fails to read the message due to some internal error.
    157      * @throws MessageFormatException if this type conversion is invalid.
    158      */
    159     public boolean getBoolean(String name) throws JMSException {
    160         Object value = getTable().get(name);
    161         if (value == null) {
    162             return false;
    163         }
    164         if (value instanceof Boolean) {
    165             return ((Boolean) value).booleanValue();
    166         }
    167         if (value instanceof String) {
    168             return Boolean.valueOf(value.toString()).booleanValue();
    169         }
    170         else {
    171             throw new MessageFormatException(" cannot read a boolean from " + value.getClass().getName());
    172         }
    173     }
    174
    175     /***
    176      * Returns the <CODE>byte</CODE> value with the specified name.
    177      *
    178      * @param name the name of the <CODE>byte</CODE>
    179      * @return the <CODE>byte</CODE> value with the specified name
    180      * @throws JMSException           if the JMS provider fails to read the message due to some internal error.
    181      * @throws MessageFormatException if this type conversion is invalid.
    182      */
    183     public byte getByte(String name) throws JMSException {
    184         Object value = getTable().get(name);
    185         if (value == null) {
    186             return 0;
    187         }
    188         if (value instanceof Byte) {
    189             return ((Byte) value).byteValue();
    190         }
    191         if (value instanceof String) {
    192             return Byte.valueOf(value.toString()).byteValue();
    193         }
    194         else {
    195             throw new MessageFormatException(" cannot read a byte from " + value.getClass().getName());
    196         }
    197     }
    198
    199     /***
    200      * Returns the <CODE>short</CODE> value with the specified name.
    201      *
    202      * @param name the name of the <CODE>short</CODE>
    203      * @return the <CODE>short</CODE> value with the specified name
    204      * @throws JMSException           if the JMS provider fails to read the message due to some internal error.
    205      * @throws MessageFormatException if this type conversion is invalid.
    206      */
    207     public short getShort(String name) throws JMSException {
    208         Object value = getTable().get(name);
    209         if (value == null) {
    210             return 0;
    211         }
    212         if (value instanceof Short) {
    213             return ((Short) value).shortValue();
    214         }
    215         if (value instanceof Byte) {
    216             return ((Byte) value).shortValue();
    217         }
    218         if (value instanceof String) {
    219             return Short.valueOf(value.toString()).shortValue();
    220         }
    221         else {
    222             throw new MessageFormatException(" cannot read a short from " + value.getClass().getName());
    223         }
    224     }
    225
    226     /***
    227      * Returns the Unicode character value with the specified name.
    228      *
    229      * @param name the name of the Unicode character
    230      * @return the Unicode character value with the specified name
    231      * @throws JMSException           if the JMS provider fails to read the message due to some internal error.
    232      * @throws MessageFormatException if this type conversion is invalid.
    233      */
    234     public char getChar(String name) throws JMSException {
    235         Object value = getTable().get(name);
    236         if (value == null) {
    237             throw new NullPointerException();
    238         }
    239         if (value instanceof Character) {
    240             return ((Character) value).charValue();
    241         }
    242         else {
    243             throw new MessageFormatException(" cannot read a short from " + value.getClass().getName());
    244         }
    245     }
    246
    247     /***
    248      * Returns the <CODE>int</CODE> value with the specified name.
    249      *
    250      * @param name the name of the <CODE>int</CODE>
    251      * @return the <CODE>int</CODE> value with the specified name
    252      * @throws JMSException           if the JMS provider fails to read the message due to some internal error.
    253      * @throws MessageFormatException if this type conversion is invalid.
    254      */
    255     public int getInt(String name) throws JMSException {
    256         Object value = getTable().get(name);
    257         if (value == null) {
    258             return 0;
    259         }
    260         if (value instanceof Integer) {
    261             return ((Integer) value).intValue();
    262         }
    263         if (value instanceof Short) {
    264             return ((Short) value).intValue();
    265         }
    266         if (value instanceof Byte) {
    267             return ((Byte) value).intValue();
    268         }
    269         if (value instanceof String) {
    270             return Integer.valueOf(value.toString()).intValue();
    271         }
    272         else {
    273             throw new MessageFormatException(" cannot read an int from " + value.getClass().getName());
    274         }
    275     }
    276
    277     /***
    278      * Returns the <CODE>long</CODE> value with the specified name.
    279      *
    280      * @param name the name of the <CODE>long</CODE>
    281      * @return the <CODE>long</CODE> value with the specified name
    282      * @throws JMSException           if the JMS provider fails to read the message due to some internal error.
    283      * @throws MessageFormatException if this type conversion is invalid.
    284      */
    285     public long getLong(String name) throws JMSException {
    286         Object value = getTable().get(name);
    287         if (value == null) {
    288             return 0;
    289         }
    290         if (value instanceof Long) {
    291             return ((Long) value).longValue();
    292         }
    293         if (value instanceof Integer) {
    294             return ((Integer) value).longValue();
    295         }
    296         if (value instanceof Short) {
    297             return ((Short) value).longValue();
    298         }
    299         if (value instanceof Byte) {
    300             return ((Byte) value).longValue();
    301         }
    302         if (value instanceof String) {
    303             return Long.valueOf(value.toString()).longValue();
    304         }
    305         else {
    306             throw new MessageFormatException(" cannot read a long from " + value.getClass().getName());
    307         }
    308     }
    309
    310     /***
    311      * Returns the <CODE>float</CODE> value with the specified name.
    312      *
    313      * @param name the name of the <CODE>float</CODE>
    314      * @return the <CODE>float</CODE> value with the specified name
    315      * @throws JMSException           if the JMS provider fails to read the message due to some internal error.
    316      * @throws MessageFormatException if this type conversion is invalid.
    317      */
    318     public float getFloat(String name) throws JMSException {
    319         Object value = getTable().get(name);
    320         if (value == null) {
    321             return 0;
    322         }
    323         if (value instanceof Float) {
    324             return ((Float) value).floatValue();
    325         }
    326         if (value instanceof String) {
    327             return Float.valueOf(value.toString()).floatValue();
    328         }
    329         else {
    330             throw new MessageFormatException(" cannot read a float from " + value.getClass().getName());
    331         }
    332     }
    333
    334     /***
    335      * Returns the <CODE>double</CODE> value with the specified name.
    336      *
    337      * @param name the name of the <CODE>double</CODE>
    338      * @return the <CODE>double</CODE> value with the specified name
    339      * @throws JMSException           if the JMS provider fails to read the message due to some internal error.
    340      * @throws MessageFormatException if this type conversion is invalid.
    341      */
    342     public double getDouble(String name) throws JMSException {
    343         Object value = getTable().get(name);
    344         if (value == null) {
    345             return 0;
    346         }
    347         if (value instanceof Double) {
    348             return ((Double) value).doubleValue();
    349         }
    350         if (value instanceof Float) {
    351             return ((Float) value).floatValue();
    352         }
    353         if (value instanceof String) {
    354             return Float.valueOf(value.toString()).floatValue();
    355         }
    356         else {
    357             throw new MessageFormatException(" cannot read a double from " + value.getClass().getName());
    358         }
    359     }
    360
    361     /***
    362      * Returns the <CODE>String</CODE> value with the specified name.
    363      *
    364      * @param name the name of the <CODE>String</CODE>
    365      * @return the <CODE>String</CODE> value with the specified name; if there is no item by this name, a null value
    366      *         is returned
    367      * @throws JMSException           if the JMS provider fails to read the message due to some internal error.
    368      * @throws MessageFormatException if this type conversion is invalid.
    369      */
    370     public String getString(String name) throws JMSException {
    371         Object value = getTable().get(name);
    372         if (value == null) {
    373             return null;
    374         }
    375         if (value instanceof byte[]) {
    376             throw new MessageFormatException("Use getBytes to read a byte array");
    377         }
    378         else {
    379             return value.toString();
    380         }
    381     }
    382
    383     /***
    384      * Returns the byte array value with the specified name.
    385      *
    386      * @param name the name of the byte array
    387      * @return a copy of the byte array value with the specified name; if there is no item by this name, a null value
    388      *         is returned.
    389      * @throws JMSException           if the JMS provider fails to read the message due to some internal error.
    390      * @throws MessageFormatException if this type conversion is invalid.
    391      */
    392     public byte[] getBytes(String name) throws JMSException {
    393         Object value = getTable().get(name);
    394         if (value instanceof byte[]) { //this will be true if the value is null
    395             return (byte[]) value;
    396         }
    397         else {
    398             throw new MessageFormatException(" cannot read a byte[] from " + value.getClass().getName());
    399         }
    400     }
    401
    402     /***
    403      * Returns the value of the object with the specified name.
    404      * <P>
    405      * This method can be used to return, in objectified format, an object in the Java programming language ("Java
    406      * object") that had been stored in the Map with the equivalent <CODE>setObject</CODE> method call, or its
    407      * equivalent primitive <CODE>set <I>type </I></CODE> method.
    408      * <P>
    409      * Note that byte values are returned as <CODE>byte[]</CODE>, not <CODE>Byte[]</CODE>.
    410      *
    411      * @param name the name of the Java object
    412      * @return a copy of the Java object value with the specified name, in objectified format (for example, if the
    413      *         object was set as an <CODE>int</CODE>, an <CODE>Integer</CODE> is returned); if there is no item by this
    414      *         name, a null value is returned
    415      * @throws JMSException if the JMS provider fails to read the message due to some internal error.
    416      */
    417     public Object getObject(String name) throws JMSException {
    418         return getTable().get(name);
    419     }
    420
    421     /***
    422      * Returns an <CODE>Enumeration</CODE> of all the names in the <CODE>MapMessage</CODE> object.
    423      *
    424      * @return an enumeration of all the names in this <CODE>MapMessage</CODE>
    425      * @throws JMSException
    426      */
    427     public Enumeration getMapNames() throws JMSException {
    428         return getTable().keys();
    429     }
    430
    431     /***
    432      * Sets a <CODE>boolean</CODE> value with the specified name into the Map.
    433      *
    434      * @param name  the name of the <CODE>boolean</CODE>
    435      * @param value the <CODE>boolean</CODE> value to set in the Map
    436      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    437      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    438      * @throws MessageNotWriteableException if the message is in read-only mode.
    439      */
    440     public void setBoolean(String name, boolean value) throws JMSException {
    441         initializeWriting();
    442         getTable().put(name, (value) ? Boolean.TRUE : Boolean.FALSE);
    443     }
    444
    445     /***
    446      * Sets a <CODE>byte</CODE> value with the specified name into the Map.
    447      *
    448      * @param name  the name of the <CODE>byte</CODE>
    449      * @param value the <CODE>byte</CODE> value to set in the Map
    450      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    451      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    452      * @throws MessageNotWriteableException if the message is in read-only mode.
    453      */
    454     public void setByte(String name, byte value) throws JMSException {
    455         initializeWriting();
    456         getTable().put(name, new Byte(value));
    457     }
    458
    459     /***
    460      * Sets a <CODE>short</CODE> value with the specified name into the Map.
    461      *
    462      * @param name  the name of the <CODE>short</CODE>
    463      * @param value the <CODE>short</CODE> value to set in the Map
    464      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    465      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    466      * @throws MessageNotWriteableException if the message is in read-only mode.
    467      */
    468     public void setShort(String name, short value) throws JMSException {
    469         initializeWriting();
    470         getTable().put(name, new Short(value));
    471     }
    472
    473     /***
    474      * Sets a Unicode character value with the specified name into the Map.
    475      *
    476      * @param name  the name of the Unicode character
    477      * @param value the Unicode character value to set in the Map
    478      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    479      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    480      * @throws MessageNotWriteableException if the message is in read-only mode.
    481      */
    482     public void setChar(String name, char value) throws JMSException {
    483         initializeWriting();
    484         getTable().put(name, new Character(value));
    485     }
    486
    487     /***
    488      * Sets an <CODE>int</CODE> value with the specified name into the Map.
    489      *
    490      * @param name  the name of the <CODE>int</CODE>
    491      * @param value the <CODE>int</CODE> value to set in the Map
    492      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    493      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    494      * @throws MessageNotWriteableException if the message is in read-only mode.
    495      */
    496     public void setInt(String name, int value) throws JMSException {
    497         initializeWriting();
    498         getTable().put(name, new Integer(value));
    499     }
    500
    501     /***
    502      * Sets a <CODE>long</CODE> value with the specified name into the Map.
    503      *
    504      * @param name  the name of the <CODE>long</CODE>
    505      * @param value the <CODE>long</CODE> value to set in the Map
    506      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    507      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    508      * @throws MessageNotWriteableException if the message is in read-only mode.
    509      */
    510     public void setLong(String name, long value) throws JMSException {
    511         initializeWriting();
    512         getTable().put(name, new Long(value));
    513     }
    514
    515     /***
    516      * Sets a <CODE>float</CODE> value with the specified name into the Map.
    517      *
    518      * @param name  the name of the <CODE>float</CODE>
    519      * @param value the <CODE>float</CODE> value to set in the Map
    520      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    521      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    522      * @throws MessageNotWriteableException if the message is in read-only mode.
    523      */
    524     public void setFloat(String name, float value) throws JMSException {
    525         initializeWriting();
    526         getTable().put(name, new Float(value));
    527     }
    528
    529     /***
    530      * Sets a <CODE>double</CODE> value with the specified name into the Map.
    531      *
    532      * @param name  the name of the <CODE>double</CODE>
    533      * @param value the <CODE>double</CODE> value to set in the Map
    534      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    535      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    536      * @throws MessageNotWriteableException if the message is in read-only mode.
    537      */
    538     public void setDouble(String name, double value) throws JMSException {
    539         initializeWriting();
    540         getTable().put(name, new Double(value));
    541     }
    542
    543     /***
    544      * Sets a <CODE>String</CODE> value with the specified name into the Map.
    545      *
    546      * @param name  the name of the <CODE>String</CODE>
    547      * @param value the <CODE>String</CODE> value to set in the Map
    548      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    549      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    550      * @throws MessageNotWriteableException if the message is in read-only mode.
    551      */
    552     public void setString(String name, String value) throws JMSException {
    553         initializeWriting();
    554         getTable().put(name, value);
    555     }
    556
    557     /***
    558      * Sets a byte array value with the specified name into the Map.
    559      *
    560      * @param name  the name of the byte array
    561      * @param value the byte array value to set in the Map; the array is copied so that the value for <CODE>name
    562      *              </CODE> will not be altered by future modifications
    563      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    564      * @throws NullPointerException         if the name is null, or if the name is an empty string.
    565      * @throws MessageNotWriteableException if the message is in read-only mode.
    566      */
    567     public void setBytes(String name, byte[] value) throws JMSException {
    568         initializeWriting();
    569         getTable().put(name, value);
    570     }
    571
    572     /***
    573      * Sets a portion of the byte array value with the specified name into the Map.
    574      *
    575      * @param name   the name of the byte array
    576      * @param value  the byte array value to set in the Map
    577      * @param offset the initial offset within the byte array
    578      * @param length the number of bytes to use
    579      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    580      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    581      * @throws MessageNotWriteableException if the message is in read-only mode.
    582      */
    583     public void setBytes(String name, byte[] value, int offset, int length) throws JMSException {
    584         initializeWriting();
    585         byte[] data = new byte[length];
    586         System.arraycopy(value, offset, data, 0, length);
    587         getTable().put(name, data);
    588     }
    589
    590     /***
    591      * Sets an object value with the specified name into the Map.
    592      * <P>
    593      * This method works only for the objectified primitive object types (<code>Integer</code>,<code>Double</code>,
    594      * <code>Long</code> &nbsp;...), <code>String</code> objects, and byte arrays.
    595      *
    596      * @param name  the name of the Java object
    597      * @param value the Java object value to set in the Map
    598      * @throws JMSException                 if the JMS provider fails to write the message due to some internal error.
    599      * @throws IllegalArgumentException     if the name is null or if the name is an empty string.
    600      * @throws MessageFormatException       if the object is invalid.
    601      * @throws MessageNotWriteableException if the message is in read-only mode.
    602      */
    603     public void setObject(String name, Object value) throws JMSException {
    604         initializeWriting();
    605         if (value instanceof Number || value instanceof String || value instanceof Boolean || value instanceof Byte
    606                 || value instanceof Character || value instanceof byte[]) {
    607             getTable().put(name, value);
    608         }
    609         else {
    610             throw new MessageFormatException(value.getClass() + " is not a primitive type");
    611         }
    612     }
    613
    614     protected void writeBody(DataOutput dataOut) throws IOException {
    615         super.writeMapProperties(theTable, dataOut);
    616         theTable = null;
    617     }
    618
    619     protected void readBody(DataInput dataIn) throws IOException {
    620         theTable = super.readMapProperties(dataIn);
    621     }
    622
    623     /***
    624      * Indicates whether an item exists in this <CODE>MapMessage</CODE> object.
    625      *
    626      * @param name the name of the item to test
    627      * @return true if the item exists
    628      * @throws JMSException if the JMS provider fails to determine if the item exists due to some internal error.
    629      */
    630     public boolean itemExists(String name) throws JMSException {
    631         return getTable().containsKey(name);
    632     }
    633
    634     private void initializeWriting() throws MessageNotWriteableException {
    635         if (super.readOnlyMessage) {
    636             throw new MessageNotWriteableException("This message is in read-only mode");
    637         }
    638     }
    639 }