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