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 private void storeContent() {
135 try {
136 if (getContent() == null && !map.isEmpty()) {
137 ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
138 OutputStream os = bytesOut;
139 ActiveMQConnection connection = getConnection();
140 if (connection != null && connection.isUseCompression()) {
141 compressed = true;
142 os = new DeflaterOutputStream(os);
143 }
144 DataOutputStream dataOut = new DataOutputStream(os);
145 MarshallingSupport.marshalPrimitiveMap(map, dataOut);
146 dataOut.close();
147 setContent(bytesOut.toByteSequence());
148 }
149 } catch (IOException e) {
150 throw new RuntimeException(e);
151 }
152 }
153
154 /**
155 * Builds the message body from data
156 *
157 * @throws JMSException
158 * @throws IOException
159 */
160 private void loadContent() throws JMSException {
161 try {
162 if (getContent() != null && map.isEmpty()) {
163 ByteSequence content = getContent();
164 InputStream is = new ByteArrayInputStream(content);
165 if (isCompressed()) {
166 is = new InflaterInputStream(is);
167 }
168 DataInputStream dataIn = new DataInputStream(is);
169 map = MarshallingSupport.unmarshalPrimitiveMap(dataIn);
170 dataIn.close();
171 }
172 } catch (IOException e) {
173 throw JMSExceptionSupport.create(e);
174 }
175 }
176
177 public byte getDataStructureType() {
178 return DATA_STRUCTURE_TYPE;
179 }
180
181 public String getJMSXMimeType() {
182 return "jms/map-message";
183 }
184
185 /**
186 * Clears out the message body. Clearing a message's body does not clear its
187 * header values or property entries.
188 * <P>
189 * If this message body was read-only, calling this method leaves the
190 * message body in the same state as an empty body in a newly created
191 * message.
192 */
193 public void clearBody() throws JMSException {
194 super.clearBody();
195 map.clear();
196 }
197
198 /**
199 * Returns the <CODE>boolean</CODE> value with the specified name.
200 *
201 * @param name the name of the <CODE>boolean</CODE>
202 * @return the <CODE>boolean</CODE> value with the specified name
203 * @throws JMSException if the JMS provider fails to read the message due to
204 * some internal error.
205 * @throws MessageFormatException if this type conversion is invalid.
206 */
207 public boolean getBoolean(String name) throws JMSException {
208 initializeReading();
209 Object value = map.get(name);
210 if (value == null) {
211 return false;
212 }
213 if (value instanceof Boolean) {
214 return ((Boolean)value).booleanValue();
215 }
216 if (value instanceof String) {
217 return Boolean.valueOf(value.toString()).booleanValue();
218 } else {
219 throw new MessageFormatException(" cannot read a boolean from " + value.getClass().getName());
220 }
221 }
222
223 /**
224 * Returns the <CODE>byte</CODE> value with the specified name.
225 *
226 * @param name the name of the <CODE>byte</CODE>
227 * @return the <CODE>byte</CODE> value with the specified name
228 * @throws JMSException if the JMS provider fails to read the message due to
229 * some internal error.
230 * @throws MessageFormatException if this type conversion is invalid.
231 */
232 public byte getByte(String name) throws JMSException {
233 initializeReading();
234 Object value = map.get(name);
235 if (value == null) {
236 return 0;
237 }
238 if (value instanceof Byte) {
239 return ((Byte)value).byteValue();
240 }
241 if (value instanceof String) {
242 return Byte.valueOf(value.toString()).byteValue();
243 } else {
244 throw new MessageFormatException(" cannot read a byte from " + value.getClass().getName());
245 }
246 }
247
248 /**
249 * Returns the <CODE>short</CODE> value with the specified name.
250 *
251 * @param name the name of the <CODE>short</CODE>
252 * @return the <CODE>short</CODE> value with the specified name
253 * @throws JMSException if the JMS provider fails to read the message due to
254 * some internal error.
255 * @throws MessageFormatException if this type conversion is invalid.
256 */
257 public short getShort(String name) throws JMSException {
258 initializeReading();
259 Object value = map.get(name);
260 if (value == null) {
261 return 0;
262 }
263 if (value instanceof Short) {
264 return ((Short)value).shortValue();
265 }
266 if (value instanceof Byte) {
267 return ((Byte)value).shortValue();
268 }
269 if (value instanceof String) {
270 return Short.valueOf(value.toString()).shortValue();
271 } else {
272 throw new MessageFormatException(" cannot read a short from " + value.getClass().getName());
273 }
274 }
275
276 /**
277 * Returns the Unicode character value with the specified name.
278 *
279 * @param name the name of the Unicode character
280 * @return the Unicode character value with the specified name
281 * @throws JMSException if the JMS provider fails to read the message due to
282 * some internal error.
283 * @throws MessageFormatException if this type conversion is invalid.
284 */
285 public char getChar(String name) throws JMSException {
286 initializeReading();
287 Object value = map.get(name);
288 if (value == null) {
289 throw new NullPointerException();
290 }
291 if (value instanceof Character) {
292 return ((Character)value).charValue();
293 } else {
294 throw new MessageFormatException(" cannot read a short from " + value.getClass().getName());
295 }
296 }
297
298 /**
299 * Returns the <CODE>int</CODE> value with the specified name.
300 *
301 * @param name the name of the <CODE>int</CODE>
302 * @return the <CODE>int</CODE> value with the specified name
303 * @throws JMSException if the JMS provider fails to read the message due to
304 * some internal error.
305 * @throws MessageFormatException if this type conversion is invalid.
306 */
307 public int getInt(String name) throws JMSException {
308 initializeReading();
309 Object value = map.get(name);
310 if (value == null) {
311 return 0;
312 }
313 if (value instanceof Integer) {
314 return ((Integer)value).intValue();
315 }
316 if (value instanceof Short) {
317 return ((Short)value).intValue();
318 }
319 if (value instanceof Byte) {
320 return ((Byte)value).intValue();
321 }
322 if (value instanceof String) {
323 return Integer.valueOf(value.toString()).intValue();
324 } else {
325 throw new MessageFormatException(" cannot read an int from " + value.getClass().getName());
326 }
327 }
328
329 /**
330 * Returns the <CODE>long</CODE> value with the specified name.
331 *
332 * @param name the name of the <CODE>long</CODE>
333 * @return the <CODE>long</CODE> value with the specified name
334 * @throws JMSException if the JMS provider fails to read the message due to
335 * some internal error.
336 * @throws MessageFormatException if this type conversion is invalid.
337 */
338 public long getLong(String name) throws JMSException {
339 initializeReading();
340 Object value = map.get(name);
341 if (value == null) {
342 return 0;
343 }
344 if (value instanceof Long) {
345 return ((Long)value).longValue();
346 }
347 if (value instanceof Integer) {
348 return ((Integer)value).longValue();
349 }
350 if (value instanceof Short) {
351 return ((Short)value).longValue();
352 }
353 if (value instanceof Byte) {
354 return ((Byte)value).longValue();
355 }
356 if (value instanceof String) {
357 return Long.valueOf(value.toString()).longValue();
358 } else {
359 throw new MessageFormatException(" cannot read a long from " + value.getClass().getName());
360 }
361 }
362
363 /**
364 * Returns the <CODE>float</CODE> value with the specified name.
365 *
366 * @param name the name of the <CODE>float</CODE>
367 * @return the <CODE>float</CODE> value with the specified name
368 * @throws JMSException if the JMS provider fails to read the message due to
369 * some internal error.
370 * @throws MessageFormatException if this type conversion is invalid.
371 */
372 public float getFloat(String name) throws JMSException {
373 initializeReading();
374 Object value = map.get(name);
375 if (value == null) {
376 return 0;
377 }
378 if (value instanceof Float) {
379 return ((Float)value).floatValue();
380 }
381 if (value instanceof String) {
382 return Float.valueOf(value.toString()).floatValue();
383 } else {
384 throw new MessageFormatException(" cannot read a float from " + value.getClass().getName());
385 }
386 }
387
388 /**
389 * Returns the <CODE>double</CODE> value with the specified name.
390 *
391 * @param name the name of the <CODE>double</CODE>
392 * @return the <CODE>double</CODE> value with the specified name
393 * @throws JMSException if the JMS provider fails to read the message due to
394 * some internal error.
395 * @throws MessageFormatException if this type conversion is invalid.
396 */
397 public double getDouble(String name) throws JMSException {
398 initializeReading();
399 Object value = map.get(name);
400 if (value == null) {
401 return 0;
402 }
403 if (value instanceof Double) {
404 return ((Double)value).doubleValue();
405 }
406 if (value instanceof Float) {
407 return ((Float)value).floatValue();
408 }
409 if (value instanceof String) {
410 return Float.valueOf(value.toString()).floatValue();
411 } else {
412 throw new MessageFormatException(" cannot read a double from " + value.getClass().getName());
413 }
414 }
415
416 /**
417 * Returns the <CODE>String</CODE> value with the specified name.
418 *
419 * @param name the name of the <CODE>String</CODE>
420 * @return the <CODE>String</CODE> value with the specified name; if there
421 * is no item by this name, a null value is returned
422 * @throws JMSException if the JMS provider fails to read the message due to
423 * some internal error.
424 * @throws MessageFormatException if this type conversion is invalid.
425 */
426 public String getString(String name) throws JMSException {
427 initializeReading();
428 Object value = map.get(name);
429 if (value == null) {
430 return null;
431 }
432 if (value instanceof byte[]) {
433 throw new MessageFormatException("Use getBytes to read a byte array");
434 } else {
435 return value.toString();
436 }
437 }
438
439 /**
440 * Returns the byte array value with the specified name.
441 *
442 * @param name the name of the byte array
443 * @return a copy of the byte array value with the specified name; if there
444 * is no item by this name, a null value is returned.
445 * @throws JMSException if the JMS provider fails to read the message due to
446 * some internal error.
447 * @throws MessageFormatException if this type conversion is invalid.
448 */
449 public byte[] getBytes(String name) throws JMSException {
450 initializeReading();
451 Object value = map.get(name);
452 if (value instanceof byte[]) {
453 return (byte[])value;
454 } else {
455 throw new MessageFormatException(" cannot read a byte[] from " + value.getClass().getName());
456 }
457 }
458
459 /**
460 * Returns the value of the object with the specified name.
461 * <P>
462 * This method can be used to return, in objectified format, an object in
463 * the Java programming language ("Java object") that had been stored in the
464 * Map with the equivalent <CODE>setObject</CODE> method call, or its
465 * equivalent primitive <CODE>set <I>type </I></CODE> method.
466 * <P>
467 * Note that byte values are returned as <CODE>byte[]</CODE>, not
468 * <CODE>Byte[]</CODE>.
469 *
470 * @param name the name of the Java object
471 * @return a copy of the Java object value with the specified name, in
472 * objectified format (for example, if the object was set as an
473 * <CODE>int</CODE>, an <CODE>Integer</CODE> is returned); if
474 * there is no item by this name, a null value is returned
475 * @throws JMSException if the JMS provider fails to read the message due to
476 * some internal error.
477 */
478 public Object getObject(String name) throws JMSException {
479 initializeReading();
480 return map.get(name);
481 }
482
483 /**
484 * Returns an <CODE>Enumeration</CODE> of all the names in the
485 * <CODE>MapMessage</CODE> object.
486 *
487 * @return an enumeration of all the names in this <CODE>MapMessage</CODE>
488 * @throws JMSException
489 */
490 public Enumeration<String> getMapNames() throws JMSException {
491 initializeReading();
492 return Collections.enumeration(map.keySet());
493 }
494
495 protected void put(String name, Object value) throws JMSException {
496 if (name == null) {
497 throw new IllegalArgumentException("The name of the property cannot be null.");
498 }
499 if (name.length() == 0) {
500 throw new IllegalArgumentException("The name of the property cannot be an emprty string.");
501 }
502 map.put(name, value);
503 }
504
505 /**
506 * Sets a <CODE>boolean</CODE> value with the specified name into the Map.
507 *
508 * @param name the name of the <CODE>boolean</CODE>
509 * @param value the <CODE>boolean</CODE> value to set in the Map
510 * @throws JMSException if the JMS provider fails to write the message due
511 * to some internal error.
512 * @throws IllegalArgumentException if the name is null or if the name is an
513 * empty string.
514 * @throws MessageNotWriteableException if the message is in read-only mode.
515 */
516 public void setBoolean(String name, boolean value) throws JMSException {
517 initializeWriting();
518 put(name, value ? Boolean.TRUE : Boolean.FALSE);
519 }
520
521 /**
522 * Sets a <CODE>byte</CODE> value with the specified name into the Map.
523 *
524 * @param name the name of the <CODE>byte</CODE>
525 * @param value the <CODE>byte</CODE> value to set in the Map
526 * @throws JMSException if the JMS provider fails to write the message due
527 * to some internal error.
528 * @throws IllegalArgumentException if the name is null or if the name is an
529 * empty string.
530 * @throws MessageNotWriteableException if the message is in read-only mode.
531 */
532 public void setByte(String name, byte value) throws JMSException {
533 initializeWriting();
534 put(name, Byte.valueOf(value));
535 }
536
537 /**
538 * Sets a <CODE>short</CODE> value with the specified name into the Map.
539 *
540 * @param name the name of the <CODE>short</CODE>
541 * @param value the <CODE>short</CODE> value to set in the Map
542 * @throws JMSException if the JMS provider fails to write the message due
543 * to some internal error.
544 * @throws IllegalArgumentException if the name is null or if the name is an
545 * empty string.
546 * @throws MessageNotWriteableException if the message is in read-only mode.
547 */
548 public void setShort(String name, short value) throws JMSException {
549 initializeWriting();
550 put(name, Short.valueOf(value));
551 }
552
553 /**
554 * Sets a Unicode character value with the specified name into the Map.
555 *
556 * @param name the name of the Unicode character
557 * @param value the Unicode character value to set in the Map
558 * @throws JMSException if the JMS provider fails to write the message due
559 * to some internal error.
560 * @throws IllegalArgumentException if the name is null or if the name is an
561 * empty string.
562 * @throws MessageNotWriteableException if the message is in read-only mode.
563 */
564 public void setChar(String name, char value) throws JMSException {
565 initializeWriting();
566 put(name, Character.valueOf(value));
567 }
568
569 /**
570 * Sets an <CODE>int</CODE> value with the specified name into the Map.
571 *
572 * @param name the name of the <CODE>int</CODE>
573 * @param value the <CODE>int</CODE> value to set in the Map
574 * @throws JMSException if the JMS provider fails to write the message due
575 * to some internal error.
576 * @throws IllegalArgumentException if the name is null or if the name is an
577 * empty string.
578 * @throws MessageNotWriteableException if the message is in read-only mode.
579 */
580 public void setInt(String name, int value) throws JMSException {
581 initializeWriting();
582 put(name, Integer.valueOf(value));
583 }
584
585 /**
586 * Sets a <CODE>long</CODE> value with the specified name into the Map.
587 *
588 * @param name the name of the <CODE>long</CODE>
589 * @param value the <CODE>long</CODE> value to set in the Map
590 * @throws JMSException if the JMS provider fails to write the message due
591 * to some internal error.
592 * @throws IllegalArgumentException if the name is null or if the name is an
593 * empty string.
594 * @throws MessageNotWriteableException if the message is in read-only mode.
595 */
596 public void setLong(String name, long value) throws JMSException {
597 initializeWriting();
598 put(name, Long.valueOf(value));
599 }
600
601 /**
602 * Sets a <CODE>float</CODE> value with the specified name into the Map.
603 *
604 * @param name the name of the <CODE>float</CODE>
605 * @param value the <CODE>float</CODE> value to set in the Map
606 * @throws JMSException if the JMS provider fails to write the message due
607 * to some internal error.
608 * @throws IllegalArgumentException if the name is null or if the name is an
609 * empty string.
610 * @throws MessageNotWriteableException if the message is in read-only mode.
611 */
612 public void setFloat(String name, float value) throws JMSException {
613 initializeWriting();
614 put(name, new Float(value));
615 }
616
617 /**
618 * Sets a <CODE>double</CODE> value with the specified name into the Map.
619 *
620 * @param name the name of the <CODE>double</CODE>
621 * @param value the <CODE>double</CODE> value to set in the Map
622 * @throws JMSException if the JMS provider fails to write the message due
623 * to some internal error.
624 * @throws IllegalArgumentException if the name is null or if the name is an
625 * empty string.
626 * @throws MessageNotWriteableException if the message is in read-only mode.
627 */
628 public void setDouble(String name, double value) throws JMSException {
629 initializeWriting();
630 put(name, new Double(value));
631 }
632
633 /**
634 * Sets a <CODE>String</CODE> value with the specified name into the Map.
635 *
636 * @param name the name of the <CODE>String</CODE>
637 * @param value the <CODE>String</CODE> value to set in the Map
638 * @throws JMSException if the JMS provider fails to write the message due
639 * to some internal error.
640 * @throws IllegalArgumentException if the name is null or if the name is an
641 * empty string.
642 * @throws MessageNotWriteableException if the message is in read-only mode.
643 */
644 public void setString(String name, String value) throws JMSException {
645 initializeWriting();
646 put(name, value);
647 }
648
649 /**
650 * Sets a byte array value with the specified name into the Map.
651 *
652 * @param name the name of the byte array
653 * @param value the byte array value to set in the Map; the array is copied
654 * so that the value for <CODE>name </CODE> will not be
655 * altered by future modifications
656 * @throws JMSException if the JMS provider fails to write the message due
657 * to some internal error.
658 * @throws NullPointerException if the name is null, or if the name is an
659 * empty string.
660 * @throws MessageNotWriteableException if the message is in read-only mode.
661 */
662 public void setBytes(String name, byte[] value) throws JMSException {
663 initializeWriting();
664 if (value != null) {
665 put(name, value);
666 } else {
667 map.remove(name);
668 }
669 }
670
671 /**
672 * Sets a portion of the byte array value with the specified name into the
673 * Map.
674 *
675 * @param name the name of the byte array
676 * @param value the byte array value to set in the Map
677 * @param offset the initial offset within the byte array
678 * @param length the number of bytes to use
679 * @throws JMSException if the JMS provider fails to write the message due
680 * to some internal error.
681 * @throws IllegalArgumentException if the name is null or if the name is an
682 * empty string.
683 * @throws MessageNotWriteableException if the message is in read-only mode.
684 */
685 public void setBytes(String name, byte[] value, int offset, int length) throws JMSException {
686 initializeWriting();
687 byte[] data = new byte[length];
688 System.arraycopy(value, offset, data, 0, length);
689 put(name, data);
690 }
691
692 /**
693 * Sets an object value with the specified name into the Map.
694 * <P>
695 * This method works only for the objectified primitive object types (<code>Integer</code>,<code>Double</code>,
696 * <code>Long</code> ...), <code>String</code> objects, and byte
697 * arrays.
698 *
699 * @param name the name of the Java object
700 * @param value the Java object value to set in the Map
701 * @throws JMSException if the JMS provider fails to write the message due
702 * to some internal error.
703 * @throws IllegalArgumentException if the name is null or if the name is an
704 * empty string.
705 * @throws MessageFormatException if the object is invalid.
706 * @throws MessageNotWriteableException if the message is in read-only mode.
707 */
708 public void setObject(String name, Object value) throws JMSException {
709 initializeWriting();
710 if (value != null) {
711 // byte[] not allowed on properties
712 if (!(value instanceof byte[])) {
713 checkValidObject(value);
714 }
715 put(name, value);
716 } else {
717 put(name, null);
718 }
719 }
720
721 /**
722 * Indicates whether an item exists in this <CODE>MapMessage</CODE>
723 * object.
724 *
725 * @param name the name of the item to test
726 * @return true if the item exists
727 * @throws JMSException if the JMS provider fails to determine if the item
728 * exists due to some internal error.
729 */
730 public boolean itemExists(String name) throws JMSException {
731 initializeReading();
732 return map.containsKey(name);
733 }
734
735 private void initializeReading() throws JMSException {
736 loadContent();
737 }
738
739 private void initializeWriting() throws MessageNotWriteableException {
740 checkReadOnlyBody();
741 setContent(null);
742 }
743
744 public String toString() {
745 return super.toString() + " ActiveMQMapMessage{ " + "theTable = " + map + " }";
746 }
747
748 public Map<String, Object> getContentMap() throws JMSException {
749 initializeReading();
750 return map;
751 }
752 }