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 316 if (value == null) { 317 throw new NullPointerException(); 318 } else if (value instanceof Character) { 319 return ((Character)value).charValue(); 320 } else { 321 throw new MessageFormatException(" cannot read a char 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 441 if (value == null) { 442 return 0; 443 } else if (value instanceof Double) { 444 return ((Double)value).doubleValue(); 445 } else if (value instanceof Float) { 446 return ((Float)value).floatValue(); 447 } else if (value instanceof UTF8Buffer) { 448 return Double.valueOf(value.toString()).doubleValue(); 449 } else if (value instanceof String) { 450 return Double.valueOf(value.toString()).doubleValue(); 451 } else { 452 throw new MessageFormatException("Cannot read a double from " + value.getClass().getName()); 453 } 454 } 455 456 /** 457 * Returns the <CODE>String</CODE> value with the specified name. 458 * 459 * @param name the name of the <CODE>String</CODE> 460 * @return the <CODE>String</CODE> value with the specified name; if there 461 * is no item by this name, a null value is returned 462 * @throws JMSException if the JMS provider fails to read the message due to 463 * some internal error. 464 * @throws MessageFormatException if this type conversion is invalid. 465 */ 466 @Override 467 public String getString(String name) throws JMSException { 468 initializeReading(); 469 Object value = map.get(name); 470 if (value == null) { 471 return null; 472 } 473 if (value instanceof byte[]) { 474 throw new MessageFormatException("Use getBytes to read a byte array"); 475 } else { 476 return value.toString(); 477 } 478 } 479 480 /** 481 * Returns the byte array value with the specified name. 482 * 483 * @param name the name of the byte array 484 * @return a copy of the byte array value with the specified name; if there 485 * is no item by this name, a null value is returned. 486 * @throws JMSException if the JMS provider fails to read the message due to 487 * some internal error. 488 * @throws MessageFormatException if this type conversion is invalid. 489 */ 490 @Override 491 public byte[] getBytes(String name) throws JMSException { 492 initializeReading(); 493 Object value = map.get(name); 494 if (value == null) { 495 return null; 496 } 497 498 if (value instanceof byte[]) { 499 return (byte[])value; 500 } else { 501 throw new MessageFormatException(" cannot read a byte[] from " + value.getClass().getName()); 502 } 503 } 504 505 /** 506 * Returns the value of the object with the specified name. 507 * <P> 508 * This method can be used to return, in objectified format, an object in 509 * the Java programming language ("Java object") that had been stored in the 510 * Map with the equivalent <CODE>setObject</CODE> method call, or its 511 * equivalent primitive <CODE>set <I>type </I></CODE> method. 512 * <P> 513 * Note that byte values are returned as <CODE>byte[]</CODE>, not 514 * <CODE>Byte[]</CODE>. 515 * 516 * @param name the name of the Java object 517 * @return a copy of the Java object value with the specified name, in 518 * objectified format (for example, if the object was set as an 519 * <CODE>int</CODE>, an <CODE>Integer</CODE> is returned); if 520 * there is no item by this name, a null value is returned 521 * @throws JMSException if the JMS provider fails to read the message due to 522 * some internal error. 523 */ 524 @Override 525 public Object getObject(String name) throws JMSException { 526 initializeReading(); 527 Object result = map.get(name); 528 if (result instanceof UTF8Buffer) { 529 result = result.toString(); 530 } 531 532 return result; 533 } 534 535 /** 536 * Returns an <CODE>Enumeration</CODE> of all the names in the 537 * <CODE>MapMessage</CODE> object. 538 * 539 * @return an enumeration of all the names in this <CODE>MapMessage</CODE> 540 * @throws JMSException 541 */ 542 @Override 543 public Enumeration<String> getMapNames() throws JMSException { 544 initializeReading(); 545 return Collections.enumeration(map.keySet()); 546 } 547 548 protected void put(String name, Object value) throws JMSException { 549 if (name == null) { 550 throw new IllegalArgumentException("The name of the property cannot be null."); 551 } 552 if (name.length() == 0) { 553 throw new IllegalArgumentException("The name of the property cannot be an emprty string."); 554 } 555 map.put(name, value); 556 } 557 558 /** 559 * Sets a <CODE>boolean</CODE> value with the specified name into the Map. 560 * 561 * @param name the name of the <CODE>boolean</CODE> 562 * @param value the <CODE>boolean</CODE> value to set in the Map 563 * @throws JMSException if the JMS provider fails to write the message due 564 * to some internal error. 565 * @throws IllegalArgumentException if the name is null or if the name is an 566 * empty string. 567 * @throws MessageNotWriteableException if the message is in read-only mode. 568 */ 569 @Override 570 public void setBoolean(String name, boolean value) throws JMSException { 571 initializeWriting(); 572 put(name, value ? Boolean.TRUE : Boolean.FALSE); 573 } 574 575 /** 576 * Sets a <CODE>byte</CODE> value with the specified name into the Map. 577 * 578 * @param name the name of the <CODE>byte</CODE> 579 * @param value the <CODE>byte</CODE> value to set in the Map 580 * @throws JMSException if the JMS provider fails to write the message due 581 * to some internal error. 582 * @throws IllegalArgumentException if the name is null or if the name is an 583 * empty string. 584 * @throws MessageNotWriteableException if the message is in read-only mode. 585 */ 586 @Override 587 public void setByte(String name, byte value) throws JMSException { 588 initializeWriting(); 589 put(name, Byte.valueOf(value)); 590 } 591 592 /** 593 * Sets a <CODE>short</CODE> value with the specified name into the Map. 594 * 595 * @param name the name of the <CODE>short</CODE> 596 * @param value the <CODE>short</CODE> value to set in the Map 597 * @throws JMSException if the JMS provider fails to write the message due 598 * to some internal error. 599 * @throws IllegalArgumentException if the name is null or if the name is an 600 * empty string. 601 * @throws MessageNotWriteableException if the message is in read-only mode. 602 */ 603 @Override 604 public void setShort(String name, short value) throws JMSException { 605 initializeWriting(); 606 put(name, Short.valueOf(value)); 607 } 608 609 /** 610 * Sets a Unicode character value with the specified name into the Map. 611 * 612 * @param name the name of the Unicode character 613 * @param value the Unicode character value to set in the Map 614 * @throws JMSException if the JMS provider fails to write the message due 615 * to some internal error. 616 * @throws IllegalArgumentException if the name is null or if the name is an 617 * empty string. 618 * @throws MessageNotWriteableException if the message is in read-only mode. 619 */ 620 @Override 621 public void setChar(String name, char value) throws JMSException { 622 initializeWriting(); 623 put(name, Character.valueOf(value)); 624 } 625 626 /** 627 * Sets an <CODE>int</CODE> value with the specified name into the Map. 628 * 629 * @param name the name of the <CODE>int</CODE> 630 * @param value the <CODE>int</CODE> value to set in the Map 631 * @throws JMSException if the JMS provider fails to write the message due 632 * to some internal error. 633 * @throws IllegalArgumentException if the name is null or if the name is an 634 * empty string. 635 * @throws MessageNotWriteableException if the message is in read-only mode. 636 */ 637 @Override 638 public void setInt(String name, int value) throws JMSException { 639 initializeWriting(); 640 put(name, Integer.valueOf(value)); 641 } 642 643 /** 644 * Sets a <CODE>long</CODE> value with the specified name into the Map. 645 * 646 * @param name the name of the <CODE>long</CODE> 647 * @param value the <CODE>long</CODE> value to set in the Map 648 * @throws JMSException if the JMS provider fails to write the message due 649 * to some internal error. 650 * @throws IllegalArgumentException if the name is null or if the name is an 651 * empty string. 652 * @throws MessageNotWriteableException if the message is in read-only mode. 653 */ 654 @Override 655 public void setLong(String name, long value) throws JMSException { 656 initializeWriting(); 657 put(name, Long.valueOf(value)); 658 } 659 660 /** 661 * Sets a <CODE>float</CODE> value with the specified name into the Map. 662 * 663 * @param name the name of the <CODE>float</CODE> 664 * @param value the <CODE>float</CODE> value to set in the Map 665 * @throws JMSException if the JMS provider fails to write the message due 666 * to some internal error. 667 * @throws IllegalArgumentException if the name is null or if the name is an 668 * empty string. 669 * @throws MessageNotWriteableException if the message is in read-only mode. 670 */ 671 @Override 672 public void setFloat(String name, float value) throws JMSException { 673 initializeWriting(); 674 put(name, new Float(value)); 675 } 676 677 /** 678 * Sets a <CODE>double</CODE> value with the specified name into the Map. 679 * 680 * @param name the name of the <CODE>double</CODE> 681 * @param value the <CODE>double</CODE> value to set in the Map 682 * @throws JMSException if the JMS provider fails to write the message due 683 * to some internal error. 684 * @throws IllegalArgumentException if the name is null or if the name is an 685 * empty string. 686 * @throws MessageNotWriteableException if the message is in read-only mode. 687 */ 688 @Override 689 public void setDouble(String name, double value) throws JMSException { 690 initializeWriting(); 691 put(name, new Double(value)); 692 } 693 694 /** 695 * Sets a <CODE>String</CODE> value with the specified name into the Map. 696 * 697 * @param name the name of the <CODE>String</CODE> 698 * @param value the <CODE>String</CODE> value to set in the Map 699 * @throws JMSException if the JMS provider fails to write the message due 700 * to some internal error. 701 * @throws IllegalArgumentException if the name is null or if the name is an 702 * empty string. 703 * @throws MessageNotWriteableException if the message is in read-only mode. 704 */ 705 @Override 706 public void setString(String name, String value) throws JMSException { 707 initializeWriting(); 708 put(name, value); 709 } 710 711 /** 712 * Sets a byte array value with the specified name into the Map. 713 * 714 * @param name the name of the byte array 715 * @param value the byte array value to set in the Map; the array is copied 716 * so that the value for <CODE>name </CODE> will not be 717 * altered by future modifications 718 * @throws JMSException if the JMS provider fails to write the message due 719 * to some internal error. 720 * @throws NullPointerException if the name is null, or if the name is an 721 * empty string. 722 * @throws MessageNotWriteableException if the message is in read-only mode. 723 */ 724 @Override 725 public void setBytes(String name, byte[] value) throws JMSException { 726 initializeWriting(); 727 if (value != null) { 728 put(name, value); 729 } else { 730 map.remove(name); 731 } 732 } 733 734 /** 735 * Sets a portion of the byte array value with the specified name into the 736 * Map. 737 * 738 * @param name the name of the byte array 739 * @param value the byte array value to set in the Map 740 * @param offset the initial offset within the byte array 741 * @param length the number of bytes to use 742 * @throws JMSException if the JMS provider fails to write the message due 743 * to some internal error. 744 * @throws IllegalArgumentException if the name is null or if the name is an 745 * empty string. 746 * @throws MessageNotWriteableException if the message is in read-only mode. 747 */ 748 @Override 749 public void setBytes(String name, byte[] value, int offset, int length) throws JMSException { 750 initializeWriting(); 751 byte[] data = new byte[length]; 752 System.arraycopy(value, offset, data, 0, length); 753 put(name, data); 754 } 755 756 /** 757 * Sets an object value with the specified name into the Map. 758 * <P> 759 * This method works only for the objectified primitive object types (<code>Integer</code>,<code>Double</code>, 760 * <code>Long</code> ...), <code>String</code> objects, and byte 761 * arrays. 762 * 763 * @param name the name of the Java object 764 * @param value the Java object value to set in the Map 765 * @throws JMSException if the JMS provider fails to write the message due 766 * to some internal error. 767 * @throws IllegalArgumentException if the name is null or if the name is an 768 * empty string. 769 * @throws MessageFormatException if the object is invalid. 770 * @throws MessageNotWriteableException if the message is in read-only mode. 771 */ 772 @Override 773 public void setObject(String name, Object value) throws JMSException { 774 initializeWriting(); 775 if (value != null) { 776 // byte[] not allowed on properties 777 if (!(value instanceof byte[])) { 778 checkValidObject(value); 779 } 780 put(name, value); 781 } else { 782 put(name, null); 783 } 784 } 785 786 /** 787 * Indicates whether an item exists in this <CODE>MapMessage</CODE> 788 * object. 789 * 790 * @param name the name of the item to test 791 * @return true if the item exists 792 * @throws JMSException if the JMS provider fails to determine if the item 793 * exists due to some internal error. 794 */ 795 @Override 796 public boolean itemExists(String name) throws JMSException { 797 initializeReading(); 798 return map.containsKey(name); 799 } 800 801 private void initializeReading() throws JMSException { 802 loadContent(); 803 } 804 805 private void initializeWriting() throws MessageNotWriteableException { 806 checkReadOnlyBody(); 807 setContent(null); 808 } 809 810 @Override 811 public void compress() throws IOException { 812 storeContent(); 813 super.compress(); 814 } 815 816 @Override 817 public String toString() { 818 return super.toString() + " ActiveMQMapMessage{ " + "theTable = " + map + " }"; 819 } 820 821 public Map<String, Object> getContentMap() throws JMSException { 822 initializeReading(); 823 return map; 824 } 825}