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 * <p/>
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> ...), <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 }