001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.activemq.command;
018    
019    import java.io.DataInputStream;
020    import java.io.DataOutputStream;
021    import java.io.IOException;
022    import java.io.InputStream;
023    import java.io.ObjectStreamException;
024    import java.io.OutputStream;
025    import java.util.Collections;
026    import java.util.Enumeration;
027    import java.util.HashMap;
028    import java.util.Map;
029    import java.util.zip.DeflaterOutputStream;
030    import java.util.zip.InflaterInputStream;
031    
032    import javax.jms.JMSException;
033    import javax.jms.MapMessage;
034    import javax.jms.MessageFormatException;
035    import javax.jms.MessageNotWriteableException;
036    
037    import org.apache.activemq.ActiveMQConnection;
038    import org.apache.activemq.util.ByteArrayInputStream;
039    import org.apache.activemq.util.ByteArrayOutputStream;
040    import org.apache.activemq.util.ByteSequence;
041    import org.apache.activemq.util.JMSExceptionSupport;
042    import org.apache.activemq.util.MarshallingSupport;
043    import org.apache.activemq.wireformat.WireFormat;
044    
045    /**
046     * A <CODE>MapMessage</CODE> object is used to send a set of name-value pairs.
047     * The names are <CODE>String</CODE> objects, and the values are primitive
048     * data types in the Java programming language. The names must have a value that
049     * is not null, and not an empty string. The entries can be accessed
050     * sequentially or randomly by name. The order of the entries is undefined.
051     * <CODE>MapMessage</CODE> inherits from the <CODE>Message</CODE> interface
052     * and adds a message body that contains a Map.
053     * <P>
054     * The primitive types can be read or written explicitly using methods for each
055     * type. They may also be read or written generically as objects. For instance,
056     * a call to <CODE>MapMessage.setInt("foo", 6)</CODE> is equivalent to
057     * <CODE> MapMessage.setObject("foo", new Integer(6))</CODE>. Both forms are
058     * provided, because the explicit form is convenient for static programming, and
059     * the object form is needed when types are not known at compile time.
060     * <P>
061     * When a client receives a <CODE>MapMessage</CODE>, it is in read-only mode.
062     * If a client attempts to write to the message at this point, a
063     * <CODE>MessageNotWriteableException</CODE> is thrown. If
064     * <CODE>clearBody</CODE> is called, the message can now be both read from and
065     * written to.
066     * <P>
067     * <CODE>MapMessage</CODE> objects support the following conversion table. The
068     * marked cases must be supported. The unmarked cases must throw a
069     * <CODE>JMSException</CODE>. The <CODE>String</CODE> -to-primitive
070     * conversions may throw a runtime exception if the primitive's
071     * <CODE>valueOf()</CODE> method does not accept it as a valid
072     * <CODE> String</CODE> representation of the primitive.
073     * <P>
074     * A value written as the row type can be read as the column type. <p/>
075     *
076     * <PRE>
077     * | | boolean byte short char int long float double String byte[] |----------------------------------------------------------------------
078     * |boolean | X X |byte | X X X X X |short | X X X X |char | X X |int | X X X |long | X X |float | X X X |double | X X
079     * |String | X X X X X X X X |byte[] | X |----------------------------------------------------------------------
080     * &lt;p/&gt;
081     * </PRE>
082     *
083     * <p/>
084     * <P>
085     * Attempting to read a null value as a primitive type must be treated as
086     * calling the primitive's corresponding <code>valueOf(String)</code>
087     * conversion method with a null value. Since <code>char</code> does not
088     * support a <code>String</code> conversion, attempting to read a null value
089     * as a <code>char</code> must throw a <code>NullPointerException</code>.
090     *
091     * @openwire:marshaller code="25"
092     * @see javax.jms.Session#createMapMessage()
093     * @see javax.jms.BytesMessage
094     * @see javax.jms.Message
095     * @see javax.jms.ObjectMessage
096     * @see javax.jms.StreamMessage
097     * @see javax.jms.TextMessage
098     */
099    public class ActiveMQMapMessage extends ActiveMQMessage implements MapMessage {
100    
101        public static final byte DATA_STRUCTURE_TYPE = CommandTypes.ACTIVEMQ_MAP_MESSAGE;
102    
103        protected transient Map<String, Object> map = new HashMap<String, Object>();
104    
105        private Object readResolve() throws ObjectStreamException {
106            if(this.map == null) {
107                this.map = new HashMap<String, Object>();
108            }
109            return this;
110        }
111    
112        public Message copy() {
113            ActiveMQMapMessage copy = new ActiveMQMapMessage();
114            copy(copy);
115            return copy;
116        }
117    
118        private void copy(ActiveMQMapMessage copy) {
119            storeContent();
120            super.copy(copy);
121        }
122    
123        // We only need to marshal the content if we are hitting the wire.
124        public void beforeMarshall(WireFormat wireFormat) throws IOException {
125            super.beforeMarshall(wireFormat);
126            storeContent();
127        }
128    
129        public void clearMarshalledState() throws JMSException {
130            super.clearMarshalledState();
131            map.clear();
132        }
133    
134        @Override
135        public void storeContent() {
136            try {
137                if (getContent() == null && !map.isEmpty()) {
138                    ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
139                    OutputStream os = bytesOut;
140                    ActiveMQConnection connection = getConnection();
141                    if (connection != null && connection.isUseCompression()) {
142                        compressed = true;
143                        os = new DeflaterOutputStream(os);
144                    }
145                    DataOutputStream dataOut = new DataOutputStream(os);
146                    MarshallingSupport.marshalPrimitiveMap(map, dataOut);
147                    dataOut.close();
148                    setContent(bytesOut.toByteSequence());
149                }
150            } catch (IOException e) {
151                throw new RuntimeException(e);
152            }
153        }
154    
155        /**
156         * Builds the message body from data
157         *
158         * @throws JMSException
159         * @throws IOException
160         */
161        private void loadContent() throws JMSException {
162            try {
163                if (getContent() != null && map.isEmpty()) {
164                    ByteSequence content = getContent();
165                    InputStream is = new ByteArrayInputStream(content);
166                    if (isCompressed()) {
167                        is = new InflaterInputStream(is);
168                    }
169                    DataInputStream dataIn = new DataInputStream(is);
170                    map = MarshallingSupport.unmarshalPrimitiveMap(dataIn);
171                    dataIn.close();
172                }
173            } catch (IOException e) {
174                throw JMSExceptionSupport.create(e);
175            }
176        }
177    
178        public byte getDataStructureType() {
179            return DATA_STRUCTURE_TYPE;
180        }
181    
182        public String getJMSXMimeType() {
183            return "jms/map-message";
184        }
185    
186        /**
187         * Clears out the message body. Clearing a message's body does not clear its
188         * header values or property entries.
189         * <P>
190         * If this message body was read-only, calling this method leaves the
191         * message body in the same state as an empty body in a newly created
192         * message.
193         */
194        public void clearBody() throws JMSException {
195            super.clearBody();
196            map.clear();
197        }
198    
199        /**
200         * Returns the <CODE>boolean</CODE> value with the specified name.
201         *
202         * @param name the name of the <CODE>boolean</CODE>
203         * @return the <CODE>boolean</CODE> value with the specified name
204         * @throws JMSException if the JMS provider fails to read the message due to
205         *                 some internal error.
206         * @throws MessageFormatException if this type conversion is invalid.
207         */
208        public boolean getBoolean(String name) throws JMSException {
209            initializeReading();
210            Object value = map.get(name);
211            if (value == null) {
212                return false;
213            }
214            if (value instanceof Boolean) {
215                return ((Boolean)value).booleanValue();
216            }
217            if (value instanceof String) {
218                return Boolean.valueOf(value.toString()).booleanValue();
219            } else {
220                throw new MessageFormatException(" cannot read a boolean from " + value.getClass().getName());
221            }
222        }
223    
224        /**
225         * Returns the <CODE>byte</CODE> value with the specified name.
226         *
227         * @param name the name of the <CODE>byte</CODE>
228         * @return the <CODE>byte</CODE> value with the specified name
229         * @throws JMSException if the JMS provider fails to read the message due to
230         *                 some internal error.
231         * @throws MessageFormatException if this type conversion is invalid.
232         */
233        public byte getByte(String name) throws JMSException {
234            initializeReading();
235            Object value = map.get(name);
236            if (value == null) {
237                return 0;
238            }
239            if (value instanceof Byte) {
240                return ((Byte)value).byteValue();
241            }
242            if (value instanceof String) {
243                return Byte.valueOf(value.toString()).byteValue();
244            } else {
245                throw new MessageFormatException(" cannot read a byte from " + value.getClass().getName());
246            }
247        }
248    
249        /**
250         * Returns the <CODE>short</CODE> value with the specified name.
251         *
252         * @param name the name of the <CODE>short</CODE>
253         * @return the <CODE>short</CODE> value with the specified name
254         * @throws JMSException if the JMS provider fails to read the message due to
255         *                 some internal error.
256         * @throws MessageFormatException if this type conversion is invalid.
257         */
258        public short getShort(String name) throws JMSException {
259            initializeReading();
260            Object value = map.get(name);
261            if (value == null) {
262                return 0;
263            }
264            if (value instanceof Short) {
265                return ((Short)value).shortValue();
266            }
267            if (value instanceof Byte) {
268                return ((Byte)value).shortValue();
269            }
270            if (value instanceof String) {
271                return Short.valueOf(value.toString()).shortValue();
272            } else {
273                throw new MessageFormatException(" cannot read a short from " + value.getClass().getName());
274            }
275        }
276    
277        /**
278         * Returns the Unicode character value with the specified name.
279         *
280         * @param name the name of the Unicode character
281         * @return the Unicode character value with the specified name
282         * @throws JMSException if the JMS provider fails to read the message due to
283         *                 some internal error.
284         * @throws MessageFormatException if this type conversion is invalid.
285         */
286        public char getChar(String name) throws JMSException {
287            initializeReading();
288            Object value = map.get(name);
289            if (value == null) {
290                throw new NullPointerException();
291            }
292            if (value instanceof Character) {
293                return ((Character)value).charValue();
294            } else {
295                throw new MessageFormatException(" cannot read a short from " + value.getClass().getName());
296            }
297        }
298    
299        /**
300         * Returns the <CODE>int</CODE> value with the specified name.
301         *
302         * @param name the name of the <CODE>int</CODE>
303         * @return the <CODE>int</CODE> value with the specified name
304         * @throws JMSException if the JMS provider fails to read the message due to
305         *                 some internal error.
306         * @throws MessageFormatException if this type conversion is invalid.
307         */
308        public int getInt(String name) throws JMSException {
309            initializeReading();
310            Object value = map.get(name);
311            if (value == null) {
312                return 0;
313            }
314            if (value instanceof Integer) {
315                return ((Integer)value).intValue();
316            }
317            if (value instanceof Short) {
318                return ((Short)value).intValue();
319            }
320            if (value instanceof Byte) {
321                return ((Byte)value).intValue();
322            }
323            if (value instanceof String) {
324                return Integer.valueOf(value.toString()).intValue();
325            } else {
326                throw new MessageFormatException(" cannot read an int from " + value.getClass().getName());
327            }
328        }
329    
330        /**
331         * Returns the <CODE>long</CODE> value with the specified name.
332         *
333         * @param name the name of the <CODE>long</CODE>
334         * @return the <CODE>long</CODE> value with the specified name
335         * @throws JMSException if the JMS provider fails to read the message due to
336         *                 some internal error.
337         * @throws MessageFormatException if this type conversion is invalid.
338         */
339        public long getLong(String name) throws JMSException {
340            initializeReading();
341            Object value = map.get(name);
342            if (value == null) {
343                return 0;
344            }
345            if (value instanceof Long) {
346                return ((Long)value).longValue();
347            }
348            if (value instanceof Integer) {
349                return ((Integer)value).longValue();
350            }
351            if (value instanceof Short) {
352                return ((Short)value).longValue();
353            }
354            if (value instanceof Byte) {
355                return ((Byte)value).longValue();
356            }
357            if (value instanceof String) {
358                return Long.valueOf(value.toString()).longValue();
359            } else {
360                throw new MessageFormatException(" cannot read a long from " + value.getClass().getName());
361            }
362        }
363    
364        /**
365         * Returns the <CODE>float</CODE> value with the specified name.
366         *
367         * @param name the name of the <CODE>float</CODE>
368         * @return the <CODE>float</CODE> value with the specified name
369         * @throws JMSException if the JMS provider fails to read the message due to
370         *                 some internal error.
371         * @throws MessageFormatException if this type conversion is invalid.
372         */
373        public float getFloat(String name) throws JMSException {
374            initializeReading();
375            Object value = map.get(name);
376            if (value == null) {
377                return 0;
378            }
379            if (value instanceof Float) {
380                return ((Float)value).floatValue();
381            }
382            if (value instanceof String) {
383                return Float.valueOf(value.toString()).floatValue();
384            } else {
385                throw new MessageFormatException(" cannot read a float from " + value.getClass().getName());
386            }
387        }
388    
389        /**
390         * Returns the <CODE>double</CODE> value with the specified name.
391         *
392         * @param name the name of the <CODE>double</CODE>
393         * @return the <CODE>double</CODE> value with the specified name
394         * @throws JMSException if the JMS provider fails to read the message due to
395         *                 some internal error.
396         * @throws MessageFormatException if this type conversion is invalid.
397         */
398        public double getDouble(String name) throws JMSException {
399            initializeReading();
400            Object value = map.get(name);
401            if (value == null) {
402                return 0;
403            }
404            if (value instanceof Double) {
405                return ((Double)value).doubleValue();
406            }
407            if (value instanceof Float) {
408                return ((Float)value).floatValue();
409            }
410            if (value instanceof String) {
411                return Float.valueOf(value.toString()).floatValue();
412            } else {
413                throw new MessageFormatException(" cannot read a double from " + value.getClass().getName());
414            }
415        }
416    
417        /**
418         * Returns the <CODE>String</CODE> value with the specified name.
419         *
420         * @param name the name of the <CODE>String</CODE>
421         * @return the <CODE>String</CODE> value with the specified name; if there
422         *         is no item by this name, a null value is returned
423         * @throws JMSException if the JMS provider fails to read the message due to
424         *                 some internal error.
425         * @throws MessageFormatException if this type conversion is invalid.
426         */
427        public String getString(String name) throws JMSException {
428            initializeReading();
429            Object value = map.get(name);
430            if (value == null) {
431                return null;
432            }
433            if (value instanceof byte[]) {
434                throw new MessageFormatException("Use getBytes to read a byte array");
435            } else {
436                return value.toString();
437            }
438        }
439    
440        /**
441         * Returns the byte array value with the specified name.
442         *
443         * @param name the name of the byte array
444         * @return a copy of the byte array value with the specified name; if there
445         *         is no item by this name, a null value is returned.
446         * @throws JMSException if the JMS provider fails to read the message due to
447         *                 some internal error.
448         * @throws MessageFormatException if this type conversion is invalid.
449         */
450        public byte[] getBytes(String name) throws JMSException {
451            initializeReading();
452            Object value = map.get(name);
453            if (value instanceof byte[]) {
454                return (byte[])value;
455            } else {
456                throw new MessageFormatException(" cannot read a byte[] from " + value.getClass().getName());
457            }
458        }
459    
460        /**
461         * Returns the value of the object with the specified name.
462         * <P>
463         * This method can be used to return, in objectified format, an object in
464         * the Java programming language ("Java object") that had been stored in the
465         * Map with the equivalent <CODE>setObject</CODE> method call, or its
466         * equivalent primitive <CODE>set <I>type </I></CODE> method.
467         * <P>
468         * Note that byte values are returned as <CODE>byte[]</CODE>, not
469         * <CODE>Byte[]</CODE>.
470         *
471         * @param name the name of the Java object
472         * @return a copy of the Java object value with the specified name, in
473         *         objectified format (for example, if the object was set as an
474         *         <CODE>int</CODE>, an <CODE>Integer</CODE> is returned); if
475         *         there is no item by this name, a null value is returned
476         * @throws JMSException if the JMS provider fails to read the message due to
477         *                 some internal error.
478         */
479        public Object getObject(String name) throws JMSException {
480            initializeReading();
481            return map.get(name);
482        }
483    
484        /**
485         * Returns an <CODE>Enumeration</CODE> of all the names in the
486         * <CODE>MapMessage</CODE> object.
487         *
488         * @return an enumeration of all the names in this <CODE>MapMessage</CODE>
489         * @throws JMSException
490         */
491        public Enumeration<String> getMapNames() throws JMSException {
492            initializeReading();
493            return Collections.enumeration(map.keySet());
494        }
495    
496        protected void put(String name, Object value) throws JMSException {
497            if (name == null) {
498                throw new IllegalArgumentException("The name of the property cannot be null.");
499            }
500            if (name.length() == 0) {
501                throw new IllegalArgumentException("The name of the property cannot be an emprty string.");
502            }
503            map.put(name, value);
504        }
505    
506        /**
507         * Sets a <CODE>boolean</CODE> value with the specified name into the Map.
508         *
509         * @param name the name of the <CODE>boolean</CODE>
510         * @param value the <CODE>boolean</CODE> value to set in the Map
511         * @throws JMSException if the JMS provider fails to write the message due
512         *                 to some internal error.
513         * @throws IllegalArgumentException if the name is null or if the name is an
514         *                 empty string.
515         * @throws MessageNotWriteableException if the message is in read-only mode.
516         */
517        public void setBoolean(String name, boolean value) throws JMSException {
518            initializeWriting();
519            put(name, value ? Boolean.TRUE : Boolean.FALSE);
520        }
521    
522        /**
523         * Sets a <CODE>byte</CODE> value with the specified name into the Map.
524         *
525         * @param name the name of the <CODE>byte</CODE>
526         * @param value the <CODE>byte</CODE> value to set in the Map
527         * @throws JMSException if the JMS provider fails to write the message due
528         *                 to some internal error.
529         * @throws IllegalArgumentException if the name is null or if the name is an
530         *                 empty string.
531         * @throws MessageNotWriteableException if the message is in read-only mode.
532         */
533        public void setByte(String name, byte value) throws JMSException {
534            initializeWriting();
535            put(name, Byte.valueOf(value));
536        }
537    
538        /**
539         * Sets a <CODE>short</CODE> value with the specified name into the Map.
540         *
541         * @param name the name of the <CODE>short</CODE>
542         * @param value the <CODE>short</CODE> value to set in the Map
543         * @throws JMSException if the JMS provider fails to write the message due
544         *                 to some internal error.
545         * @throws IllegalArgumentException if the name is null or if the name is an
546         *                 empty string.
547         * @throws MessageNotWriteableException if the message is in read-only mode.
548         */
549        public void setShort(String name, short value) throws JMSException {
550            initializeWriting();
551            put(name, Short.valueOf(value));
552        }
553    
554        /**
555         * Sets a Unicode character value with the specified name into the Map.
556         *
557         * @param name the name of the Unicode character
558         * @param value the Unicode character value to set in the Map
559         * @throws JMSException if the JMS provider fails to write the message due
560         *                 to some internal error.
561         * @throws IllegalArgumentException if the name is null or if the name is an
562         *                 empty string.
563         * @throws MessageNotWriteableException if the message is in read-only mode.
564         */
565        public void setChar(String name, char value) throws JMSException {
566            initializeWriting();
567            put(name, Character.valueOf(value));
568        }
569    
570        /**
571         * Sets an <CODE>int</CODE> value with the specified name into the Map.
572         *
573         * @param name the name of the <CODE>int</CODE>
574         * @param value the <CODE>int</CODE> value to set in the Map
575         * @throws JMSException if the JMS provider fails to write the message due
576         *                 to some internal error.
577         * @throws IllegalArgumentException if the name is null or if the name is an
578         *                 empty string.
579         * @throws MessageNotWriteableException if the message is in read-only mode.
580         */
581        public void setInt(String name, int value) throws JMSException {
582            initializeWriting();
583            put(name, Integer.valueOf(value));
584        }
585    
586        /**
587         * Sets a <CODE>long</CODE> value with the specified name into the Map.
588         *
589         * @param name the name of the <CODE>long</CODE>
590         * @param value the <CODE>long</CODE> value to set in the Map
591         * @throws JMSException if the JMS provider fails to write the message due
592         *                 to some internal error.
593         * @throws IllegalArgumentException if the name is null or if the name is an
594         *                 empty string.
595         * @throws MessageNotWriteableException if the message is in read-only mode.
596         */
597        public void setLong(String name, long value) throws JMSException {
598            initializeWriting();
599            put(name, Long.valueOf(value));
600        }
601    
602        /**
603         * Sets a <CODE>float</CODE> value with the specified name into the Map.
604         *
605         * @param name the name of the <CODE>float</CODE>
606         * @param value the <CODE>float</CODE> value to set in the Map
607         * @throws JMSException if the JMS provider fails to write the message due
608         *                 to some internal error.
609         * @throws IllegalArgumentException if the name is null or if the name is an
610         *                 empty string.
611         * @throws MessageNotWriteableException if the message is in read-only mode.
612         */
613        public void setFloat(String name, float value) throws JMSException {
614            initializeWriting();
615            put(name, new Float(value));
616        }
617    
618        /**
619         * Sets a <CODE>double</CODE> value with the specified name into the Map.
620         *
621         * @param name the name of the <CODE>double</CODE>
622         * @param value the <CODE>double</CODE> value to set in the Map
623         * @throws JMSException if the JMS provider fails to write the message due
624         *                 to some internal error.
625         * @throws IllegalArgumentException if the name is null or if the name is an
626         *                 empty string.
627         * @throws MessageNotWriteableException if the message is in read-only mode.
628         */
629        public void setDouble(String name, double value) throws JMSException {
630            initializeWriting();
631            put(name, new Double(value));
632        }
633    
634        /**
635         * Sets a <CODE>String</CODE> value with the specified name into the Map.
636         *
637         * @param name the name of the <CODE>String</CODE>
638         * @param value the <CODE>String</CODE> value to set in the Map
639         * @throws JMSException if the JMS provider fails to write the message due
640         *                 to some internal error.
641         * @throws IllegalArgumentException if the name is null or if the name is an
642         *                 empty string.
643         * @throws MessageNotWriteableException if the message is in read-only mode.
644         */
645        public void setString(String name, String value) throws JMSException {
646            initializeWriting();
647            put(name, value);
648        }
649    
650        /**
651         * Sets a byte array value with the specified name into the Map.
652         *
653         * @param name the name of the byte array
654         * @param value the byte array value to set in the Map; the array is copied
655         *                so that the value for <CODE>name </CODE> will not be
656         *                altered by future modifications
657         * @throws JMSException if the JMS provider fails to write the message due
658         *                 to some internal error.
659         * @throws NullPointerException if the name is null, or if the name is an
660         *                 empty string.
661         * @throws MessageNotWriteableException if the message is in read-only mode.
662         */
663        public void setBytes(String name, byte[] value) throws JMSException {
664            initializeWriting();
665            if (value != null) {
666                put(name, value);
667            } else {
668                map.remove(name);
669            }
670        }
671    
672        /**
673         * Sets a portion of the byte array value with the specified name into the
674         * Map.
675         *
676         * @param name the name of the byte array
677         * @param value the byte array value to set in the Map
678         * @param offset the initial offset within the byte array
679         * @param length the number of bytes to use
680         * @throws JMSException if the JMS provider fails to write the message due
681         *                 to some internal error.
682         * @throws IllegalArgumentException if the name is null or if the name is an
683         *                 empty string.
684         * @throws MessageNotWriteableException if the message is in read-only mode.
685         */
686        public void setBytes(String name, byte[] value, int offset, int length) throws JMSException {
687            initializeWriting();
688            byte[] data = new byte[length];
689            System.arraycopy(value, offset, data, 0, length);
690            put(name, data);
691        }
692    
693        /**
694         * Sets an object value with the specified name into the Map.
695         * <P>
696         * This method works only for the objectified primitive object types (<code>Integer</code>,<code>Double</code>,
697         * <code>Long</code> &nbsp;...), <code>String</code> objects, and byte
698         * arrays.
699         *
700         * @param name the name of the Java object
701         * @param value the Java object value to set in the Map
702         * @throws JMSException if the JMS provider fails to write the message due
703         *                 to some internal error.
704         * @throws IllegalArgumentException if the name is null or if the name is an
705         *                 empty string.
706         * @throws MessageFormatException if the object is invalid.
707         * @throws MessageNotWriteableException if the message is in read-only mode.
708         */
709        public void setObject(String name, Object value) throws JMSException {
710            initializeWriting();
711            if (value != null) {
712                // byte[] not allowed on properties
713                if (!(value instanceof byte[])) {
714                    checkValidObject(value);
715                }
716                put(name, value);
717            } else {
718                put(name, null);
719            }
720        }
721    
722        /**
723         * Indicates whether an item exists in this <CODE>MapMessage</CODE>
724         * object.
725         *
726         * @param name the name of the item to test
727         * @return true if the item exists
728         * @throws JMSException if the JMS provider fails to determine if the item
729         *                 exists due to some internal error.
730         */
731        public boolean itemExists(String name) throws JMSException {
732            initializeReading();
733            return map.containsKey(name);
734        }
735    
736        private void initializeReading() throws JMSException {
737            loadContent();
738        }
739    
740        private void initializeWriting() throws MessageNotWriteableException {
741            checkReadOnlyBody();
742            setContent(null);
743        }
744    
745        @Override
746        public void compress() throws IOException {
747            storeContent();
748            super.compress();
749        }
750    
751        public String toString() {
752            return super.toString() + " ActiveMQMapMessage{ " + "theTable = " + map + " }";
753        }
754    
755        public Map<String, Object> getContentMap() throws JMSException {
756            initializeReading();
757            return map;
758        }
759    }