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