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