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 */ 017package org.apache.activemq.command; 018 019import java.io.DataInputStream; 020import java.io.DataOutputStream; 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.ObjectStreamException; 024import java.io.OutputStream; 025import java.util.Collections; 026import java.util.Enumeration; 027import java.util.HashMap; 028import java.util.Map; 029import java.util.zip.DeflaterOutputStream; 030import java.util.zip.InflaterInputStream; 031 032import javax.jms.JMSException; 033import javax.jms.MapMessage; 034import javax.jms.MessageFormatException; 035import javax.jms.MessageNotWriteableException; 036 037import org.apache.activemq.ActiveMQConnection; 038import org.apache.activemq.util.ByteArrayInputStream; 039import org.apache.activemq.util.ByteArrayOutputStream; 040import org.apache.activemq.util.ByteSequence; 041import org.apache.activemq.util.JMSExceptionSupport; 042import org.apache.activemq.util.MarshallingSupport; 043import 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 */ 099public 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}