001 /** 002 * 003 * Copyright 2004 Protique Ltd 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 **/ 018 package org.activemq.message; 019 020 import javax.jms.BytesMessage; 021 import javax.jms.JMSException; 022 import javax.jms.MessageEOFException; 023 import javax.jms.MessageFormatException; 024 import javax.jms.MessageNotReadableException; 025 import javax.jms.MessageNotWriteableException; 026 027 import org.activemq.io.util.ByteArray; 028 import org.activemq.io.util.ByteArrayCompression; 029 030 import java.io.ByteArrayInputStream; 031 import java.io.ByteArrayOutputStream; 032 import java.io.DataInputStream; 033 import java.io.DataOutputStream; 034 import java.io.EOFException; 035 import java.io.IOException; 036 037 /** 038 * A <CODE>BytesMessage</CODE> object is used to send a message containing a stream of uninterpreted bytes. It 039 * inherits from the <CODE>Message</CODE> interface and adds a bytes message body. The receiver of the message 040 * supplies the interpretation of the bytes. 041 * <P> 042 * The <CODE>BytesMessage</CODE> methods are based largely on those found in <CODE>java.io.DataInputStream</CODE> 043 * and <CODE>java.io.DataOutputStream</CODE>. 044 * <P> 045 * This message type is for client encoding of existing message formats. If possible, one of the other self-defining 046 * message types should be used instead. 047 * <P> 048 * Although the JMS API allows the use of message properties with byte messages, they are typically not used, since the 049 * inclusion of properties may affect the format. 050 * <P> 051 * The primitive types can be written explicitly using methods for each type. They may also be written generically as 052 * objects. For instance, a call to <CODE>BytesMessage.writeInt(6)</CODE> is equivalent to <CODE> 053 * BytesMessage.writeObject(new Integer(6))</CODE>. Both forms are provided, because the explicit form is convenient 054 * for static programming, and the object form is needed when types are not known at compile time. 055 * <P> 056 * When the message is first created, and when <CODE>clearBody</CODE> is called, the body of the message is in 057 * write-only mode. After the first call to <CODE>reset</CODE> has been made, the message body is in read-only mode. 058 * After a message has been sent, the client that sent it can retain and modify it without affecting the message that 059 * has been sent. The same message object can be sent multiple times. When a message has been received, the provider 060 * has called <CODE>reset</CODE> so that the message body is in read-only mode for the client. 061 * <P> 062 * If <CODE>clearBody</CODE> is called on a message in read-only mode, the message body is cleared and the message is 063 * in write-only mode. 064 * <P> 065 * If a client attempts to read a message in write-only mode, a <CODE>MessageNotReadableException</CODE> is thrown. 066 * <P> 067 * If a client attempts to write a message in read-only mode, a <CODE>MessageNotWriteableException</CODE> is thrown. 068 * 069 * @see javax.jms.Session#createBytesMessage() 070 * @see javax.jms.MapMessage 071 * @see javax.jms.Message 072 * @see javax.jms.ObjectMessage 073 * @see javax.jms.StreamMessage 074 * @see javax.jms.TextMessage 075 */ 076 public class ActiveMQBytesMessage extends ActiveMQMessage implements BytesMessage { 077 private DataOutputStream dataOut; 078 private ByteArrayOutputStream bytesOut; 079 private DataInputStream dataIn; 080 private transient long bodyLength = 0; 081 082 /** 083 * Return the type of Packet 084 * 085 * @return integer representation of the type of Packet 086 */ 087 public int getPacketType() { 088 return ACTIVEMQ_BYTES_MESSAGE; 089 } 090 091 /** 092 * @return Returns a shallow copy of the message instance 093 * @throws JMSException 094 */ 095 public ActiveMQMessage shallowCopy() throws JMSException { 096 ActiveMQBytesMessage other = new ActiveMQBytesMessage(); 097 this.initializeOther(other); 098 try { 099 other.setBodyAsBytes(this.getBodyAsBytes()); 100 } 101 catch (IOException e) { 102 JMSException jmsEx = new JMSException("setBodyAsBytes() failed"); 103 jmsEx.setLinkedException(e); 104 throw jmsEx; 105 } 106 return other; 107 } 108 109 /** 110 * @return Returns a deep copy of the message - note the header fields are only shallow copied 111 * @throws JMSException 112 */ 113 public ActiveMQMessage deepCopy() throws JMSException { 114 ActiveMQBytesMessage other = new ActiveMQBytesMessage(); 115 this.initializeOther(other); 116 try { 117 if (this.getBodyAsBytes() != null) { 118 ByteArray data = this.getBodyAsBytes().copy(); 119 other.setBodyAsBytes(data); 120 } 121 } 122 catch (IOException e) { 123 JMSException jmsEx = new JMSException("setBodyAsBytes() failed"); 124 jmsEx.setLinkedException(e); 125 throw jmsEx; 126 } 127 return other; 128 } 129 130 /** 131 * @param bodyAsBytes The bodyAsBytes to set. 132 * @param offset 133 * @param length 134 */ 135 public void setBodyAsBytes(byte[] bodyAsBytes,int offset, int length) { 136 super.setBodyAsBytes(bodyAsBytes,offset,length); 137 dataOut = null; 138 dataIn = null; 139 } 140 141 /** 142 * @return Returns the data body 143 * @throws IOException if an exception occurs retreiving the data 144 */ 145 public ByteArray getBodyAsBytes() throws IOException { 146 if (this.dataOut != null) { 147 this.dataOut.flush(); 148 byte[] data = this.bytesOut.toByteArray(); 149 super.setBodyAsBytes(data,0,data.length); 150 dataOut.close(); 151 dataOut = null; 152 } 153 return super.getBodyAsBytes(); 154 } 155 156 157 158 /** 159 * Clears out the message body. Clearing a message's body does not clear its header values or property entries. 160 * <P> 161 * If this message body was read-only, calling this method leaves the message body in the same state as an empty 162 * body in a newly created message. 163 * 164 * @throws JMSException if the JMS provider fails to clear the message body due to some internal error. 165 */ 166 public void clearBody() throws JMSException { 167 super.clearBody(); 168 this.dataOut = null; 169 this.dataIn = null; 170 this.bytesOut = null; 171 } 172 173 /** 174 * Gets the number of bytes of the message body when the message is in read-only mode. The value returned can be 175 * used to allocate a byte array. The value returned is the entire length of the message body, regardless of where 176 * the pointer for reading the message is currently located. 177 * 178 * @return number of bytes in the message 179 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 180 * @throws MessageNotReadableException if the message is in write-only mode. 181 * @since 1.1 182 */ 183 public long getBodyLength() throws JMSException { 184 initializeReading(); 185 return bodyLength; 186 } 187 188 /** 189 * Reads a <code>boolean</code> from the bytes message stream. 190 * 191 * @return the <code>boolean</code> value read 192 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 193 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 194 * @throws MessageNotReadableException if the message is in write-only mode. 195 */ 196 public boolean readBoolean() throws JMSException { 197 initializeReading(); 198 try { 199 return this.dataIn.readBoolean(); 200 } 201 catch (EOFException eof) { 202 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 203 jmsEx.setLinkedException(eof); 204 throw jmsEx; 205 } 206 catch (IOException ioe) { 207 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 208 jmsEx.setLinkedException(ioe); 209 throw jmsEx; 210 } 211 } 212 213 /** 214 * Reads a signed 8-bit value from the bytes message stream. 215 * 216 * @return the next byte from the bytes message stream as a signed 8-bit <code>byte</code> 217 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 218 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 219 * @throws MessageNotReadableException if the message is in write-only mode. 220 */ 221 public byte readByte() throws JMSException { 222 initializeReading(); 223 try { 224 return this.dataIn.readByte(); 225 } 226 catch (EOFException eof) { 227 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 228 jmsEx.setLinkedException(eof); 229 throw jmsEx; 230 } 231 catch (IOException ioe) { 232 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 233 jmsEx.setLinkedException(ioe); 234 throw jmsEx; 235 } 236 } 237 238 /** 239 * Reads an unsigned 8-bit number from the bytes message stream. 240 * 241 * @return the next byte from the bytes message stream, interpreted as an unsigned 8-bit number 242 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 243 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 244 * @throws MessageNotReadableException if the message is in write-only mode. 245 */ 246 public int readUnsignedByte() throws JMSException { 247 initializeReading(); 248 try { 249 return this.dataIn.readUnsignedByte(); 250 } 251 catch (EOFException eof) { 252 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 253 jmsEx.setLinkedException(eof); 254 throw jmsEx; 255 } 256 catch (IOException ioe) { 257 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 258 jmsEx.setLinkedException(ioe); 259 throw jmsEx; 260 } 261 } 262 263 /** 264 * Reads a signed 16-bit number from the bytes message stream. 265 * 266 * @return the next two bytes from the bytes message stream, interpreted as a signed 16-bit number 267 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 268 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 269 * @throws MessageNotReadableException if the message is in write-only mode. 270 */ 271 public short readShort() throws JMSException { 272 initializeReading(); 273 try { 274 return this.dataIn.readShort(); 275 } 276 catch (EOFException eof) { 277 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 278 jmsEx.setLinkedException(eof); 279 throw jmsEx; 280 } 281 catch (IOException ioe) { 282 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 283 jmsEx.setLinkedException(ioe); 284 throw jmsEx; 285 } 286 } 287 288 /** 289 * Reads an unsigned 16-bit number from the bytes message stream. 290 * 291 * @return the next two bytes from the bytes message stream, interpreted as an unsigned 16-bit integer 292 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 293 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 294 * @throws MessageNotReadableException if the message is in write-only mode. 295 */ 296 public int readUnsignedShort() throws JMSException { 297 initializeReading(); 298 try { 299 return this.dataIn.readUnsignedShort(); 300 } 301 catch (EOFException eof) { 302 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 303 jmsEx.setLinkedException(eof); 304 throw jmsEx; 305 } 306 catch (IOException ioe) { 307 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 308 jmsEx.setLinkedException(ioe); 309 throw jmsEx; 310 } 311 } 312 313 /** 314 * Reads a Unicode character value from the bytes message stream. 315 * 316 * @return the next two bytes from the bytes message stream as a Unicode character 317 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 318 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 319 * @throws MessageNotReadableException if the message is in write-only mode. 320 */ 321 public char readChar() throws JMSException { 322 initializeReading(); 323 try { 324 return this.dataIn.readChar(); 325 } 326 catch (EOFException eof) { 327 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 328 jmsEx.setLinkedException(eof); 329 throw jmsEx; 330 } 331 catch (IOException ioe) { 332 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 333 jmsEx.setLinkedException(ioe); 334 throw jmsEx; 335 } 336 } 337 338 /** 339 * Reads a signed 32-bit integer from the bytes message stream. 340 * 341 * @return the next four bytes from the bytes message stream, interpreted as an <code>int</code> 342 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 343 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 344 * @throws MessageNotReadableException if the message is in write-only mode. 345 */ 346 public int readInt() throws JMSException { 347 initializeReading(); 348 try { 349 return this.dataIn.readInt(); 350 } 351 catch (EOFException eof) { 352 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 353 jmsEx.setLinkedException(eof); 354 throw jmsEx; 355 } 356 catch (IOException ioe) { 357 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 358 jmsEx.setLinkedException(ioe); 359 throw jmsEx; 360 } 361 } 362 363 /** 364 * Reads a signed 64-bit integer from the bytes message stream. 365 * 366 * @return the next eight bytes from the bytes message stream, interpreted as a <code>long</code> 367 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 368 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 369 * @throws MessageNotReadableException if the message is in write-only mode. 370 */ 371 public long readLong() throws JMSException { 372 initializeReading(); 373 try { 374 return this.dataIn.readLong(); 375 } 376 catch (EOFException eof) { 377 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 378 jmsEx.setLinkedException(eof); 379 throw jmsEx; 380 } 381 catch (IOException ioe) { 382 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 383 jmsEx.setLinkedException(ioe); 384 throw jmsEx; 385 } 386 } 387 388 /** 389 * Reads a <code>float</code> from the bytes message stream. 390 * 391 * @return the next four bytes from the bytes message stream, interpreted as a <code>float</code> 392 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 393 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 394 * @throws MessageNotReadableException if the message is in write-only mode. 395 */ 396 public float readFloat() throws JMSException { 397 initializeReading(); 398 try { 399 return this.dataIn.readFloat(); 400 } 401 catch (EOFException eof) { 402 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 403 jmsEx.setLinkedException(eof); 404 throw jmsEx; 405 } 406 catch (IOException ioe) { 407 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 408 jmsEx.setLinkedException(ioe); 409 throw jmsEx; 410 } 411 } 412 413 /** 414 * Reads a <code>double</code> from the bytes message stream. 415 * 416 * @return the next eight bytes from the bytes message stream, interpreted as a <code>double</code> 417 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 418 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 419 * @throws MessageNotReadableException if the message is in write-only mode. 420 */ 421 public double readDouble() throws JMSException { 422 initializeReading(); 423 try { 424 return this.dataIn.readDouble(); 425 } 426 catch (EOFException eof) { 427 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 428 jmsEx.setLinkedException(eof); 429 throw jmsEx; 430 } 431 catch (IOException ioe) { 432 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 433 jmsEx.setLinkedException(ioe); 434 throw jmsEx; 435 } 436 } 437 438 /** 439 * Reads a string that has been encoded using a modified UTF-8 format from the bytes message stream. 440 * <P> 441 * For more information on the UTF-8 format, see "File System Safe UCS Transformation Format (FSS_UTF)", X/Open 442 * Preliminary Specification, X/Open Company Ltd., Document Number: P316. This information also appears in ISO/IEC 443 * 10646, Annex P. 444 * 445 * @return a Unicode string from the bytes message stream 446 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 447 * @throws MessageEOFException if unexpected end of bytes stream has been reached. 448 * @throws MessageNotReadableException if the message is in write-only mode. 449 */ 450 public String readUTF() throws JMSException { 451 initializeReading(); 452 try { 453 return this.dataIn.readUTF(); 454 } 455 catch (EOFException eof) { 456 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 457 jmsEx.setLinkedException(eof); 458 throw jmsEx; 459 } 460 catch (IOException ioe) { 461 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 462 jmsEx.setLinkedException(ioe); 463 throw jmsEx; 464 } 465 } 466 467 /** 468 * Reads a byte array from the bytes message stream. 469 * <P> 470 * If the length of array <code>value</code> is less than the number of bytes remaining to be read from the 471 * stream, the array should be filled. A subsequent call reads the next increment, and so on. 472 * <P> 473 * If the number of bytes remaining in the stream is less than the length of array <code>value</code>, the bytes 474 * should be read into the array. The return value of the total number of bytes read will be less than the length 475 * of the array, indicating that there are no more bytes left to be read from the stream. The next read of the 476 * stream returns -1. 477 * 478 * @param value the buffer into which the data is read 479 * @return the total number of bytes read into the buffer, or -1 if there is no more data because the end of the 480 * stream has been reached 481 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 482 * @throws MessageNotReadableException if the message is in write-only mode. 483 */ 484 public int readBytes(byte[] value) throws JMSException { 485 return readBytes(value, value.length); 486 } 487 488 /** 489 * Reads a portion of the bytes message stream. 490 * <P> 491 * If the length of array <code>value</code> is less than the number of bytes remaining to be read from the 492 * stream, the array should be filled. A subsequent call reads the next increment, and so on. 493 * <P> 494 * If the number of bytes remaining in the stream is less than the length of array <code>value</code>, the bytes 495 * should be read into the array. The return value of the total number of bytes read will be less than the length 496 * of the array, indicating that there are no more bytes left to be read from the stream. The next read of the 497 * stream returns -1. 498 * <p/> 499 * If <code>length</code> is negative, or <code>length</code> is greater than the length of the array <code>value</code>, 500 * then an <code>IndexOutOfBoundsException</code> is thrown. No bytes will be read from the stream for this 501 * exception case. 502 * 503 * @param value the buffer into which the data is read 504 * @param length the number of bytes to read; must be less than or equal to <code>value.length</code> 505 * @return the total number of bytes read into the buffer, or -1 if there is no more data because the end of the 506 * stream has been reached 507 * @throws JMSException if the JMS provider fails to read the message due to some internal error. 508 * @throws MessageNotReadableException if the message is in write-only mode. 509 */ 510 public int readBytes(byte[] value, int length) throws JMSException { 511 initializeReading(); 512 try { 513 int n = 0; 514 while (n < length) { 515 int count = this.dataIn.read(value, n, length - n); 516 if (count < 0) { 517 break; 518 } 519 n += count; 520 } 521 if (n == 0 && length > 0) { 522 n = -1; 523 } 524 return n; 525 } 526 catch (EOFException eof) { 527 JMSException jmsEx = new MessageEOFException(eof.getMessage()); 528 jmsEx.setLinkedException(eof); 529 throw jmsEx; 530 } 531 catch (IOException ioe) { 532 JMSException jmsEx = new JMSException("Format error occured" + ioe.getMessage()); 533 jmsEx.setLinkedException(ioe); 534 throw jmsEx; 535 } 536 } 537 538 /** 539 * Writes a <code>boolean</code> to the bytes message stream as a 1-byte value. The value <code>true</code> is 540 * written as the value <code>(byte)1</code>; the value <code>false</code> is written as the value <code>(byte)0</code>. 541 * 542 * @param value the <code>boolean</code> value to be written 543 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 544 * @throws MessageNotWriteableException if the message is in read-only mode. 545 */ 546 public void writeBoolean(boolean value) throws JMSException { 547 initializeWriting(); 548 try { 549 this.dataOut.writeBoolean(value); 550 } 551 catch (IOException ioe) { 552 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 553 jmsEx.setLinkedException(ioe); 554 throw jmsEx; 555 } 556 } 557 558 /** 559 * Writes a <code>byte</code> to the bytes message stream as a 1-byte value. 560 * 561 * @param value the <code>byte</code> value to be written 562 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 563 * @throws MessageNotWriteableException if the message is in read-only mode. 564 */ 565 public void writeByte(byte value) throws JMSException { 566 initializeWriting(); 567 try { 568 this.dataOut.writeByte(value); 569 } 570 catch (IOException ioe) { 571 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 572 jmsEx.setLinkedException(ioe); 573 throw jmsEx; 574 } 575 } 576 577 /** 578 * Writes a <code>short</code> to the bytes message stream as two bytes, high byte first. 579 * 580 * @param value the <code>short</code> to be written 581 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 582 * @throws MessageNotWriteableException if the message is in read-only mode. 583 */ 584 public void writeShort(short value) throws JMSException { 585 initializeWriting(); 586 try { 587 this.dataOut.writeShort(value); 588 } 589 catch (IOException ioe) { 590 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 591 jmsEx.setLinkedException(ioe); 592 throw jmsEx; 593 } 594 } 595 596 /** 597 * Writes a <code>char</code> to the bytes message stream as a 2-byte value, high byte first. 598 * 599 * @param value the <code>char</code> value to be written 600 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 601 * @throws MessageNotWriteableException if the message is in read-only mode. 602 */ 603 public void writeChar(char value) throws JMSException { 604 initializeWriting(); 605 try { 606 this.dataOut.writeChar(value); 607 } 608 catch (IOException ioe) { 609 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 610 jmsEx.setLinkedException(ioe); 611 throw jmsEx; 612 } 613 } 614 615 /** 616 * Writes an <code>int</code> to the bytes message stream as four bytes, high byte first. 617 * 618 * @param value the <code>int</code> to be written 619 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 620 * @throws MessageNotWriteableException if the message is in read-only mode. 621 */ 622 public void writeInt(int value) throws JMSException { 623 initializeWriting(); 624 try { 625 this.dataOut.writeInt(value); 626 } 627 catch (IOException ioe) { 628 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 629 jmsEx.setLinkedException(ioe); 630 throw jmsEx; 631 } 632 } 633 634 /** 635 * Writes a <code>long</code> to the bytes message stream as eight bytes, high byte first. 636 * 637 * @param value the <code>long</code> to be written 638 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 639 * @throws MessageNotWriteableException if the message is in read-only mode. 640 */ 641 public void writeLong(long value) throws JMSException { 642 initializeWriting(); 643 try { 644 this.dataOut.writeLong(value); 645 } 646 catch (IOException ioe) { 647 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 648 jmsEx.setLinkedException(ioe); 649 throw jmsEx; 650 } 651 } 652 653 /** 654 * Converts the <code>float</code> argument to an <code>int</code> using the <code>floatToIntBits</code> 655 * method in class <code>Float</code>, and then writes that <code>int</code> value to the bytes message stream 656 * as a 4-byte quantity, high byte first. 657 * 658 * @param value the <code>float</code> value to be written 659 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 660 * @throws MessageNotWriteableException if the message is in read-only mode. 661 */ 662 public void writeFloat(float value) throws JMSException { 663 initializeWriting(); 664 try { 665 this.dataOut.writeFloat(value); 666 } 667 catch (IOException ioe) { 668 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 669 jmsEx.setLinkedException(ioe); 670 throw jmsEx; 671 } 672 } 673 674 /** 675 * Converts the <code>double</code> argument to a <code>long</code> using the <code>doubleToLongBits</code> 676 * method in class <code>Double</code>, and then writes that <code>long</code> value to the bytes message 677 * stream as an 8-byte quantity, high byte first. 678 * 679 * @param value the <code>double</code> value to be written 680 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 681 * @throws MessageNotWriteableException if the message is in read-only mode. 682 */ 683 public void writeDouble(double value) throws JMSException { 684 initializeWriting(); 685 try { 686 this.dataOut.writeDouble(value); 687 } 688 catch (IOException ioe) { 689 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 690 jmsEx.setLinkedException(ioe); 691 throw jmsEx; 692 } 693 } 694 695 /** 696 * Writes a string to the bytes message stream using UTF-8 encoding in a machine-independent manner. 697 * <P> 698 * For more information on the UTF-8 format, see "File System Safe UCS Transformation Format (FSS_UTF)", X/Open 699 * Preliminary Specification, X/Open Company Ltd., Document Number: P316. This information also appears in ISO/IEC 700 * 10646, Annex P. 701 * 702 * @param value the <code>String</code> value to be written 703 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 704 * @throws MessageNotWriteableException if the message is in read-only mode. 705 */ 706 public void writeUTF(String value) throws JMSException { 707 initializeWriting(); 708 try { 709 this.dataOut.writeUTF(value); 710 } 711 catch (IOException ioe) { 712 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 713 jmsEx.setLinkedException(ioe); 714 throw jmsEx; 715 } 716 } 717 718 /** 719 * Writes a byte array to the bytes message stream. 720 * 721 * @param value the byte array to be written 722 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 723 * @throws MessageNotWriteableException if the message is in read-only mode. 724 */ 725 public void writeBytes(byte[] value) throws JMSException { 726 initializeWriting(); 727 try { 728 this.dataOut.write(value); 729 } 730 catch (IOException ioe) { 731 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 732 jmsEx.setLinkedException(ioe); 733 throw jmsEx; 734 } 735 } 736 737 /** 738 * Writes a portion of a byte array to the bytes message stream. 739 * 740 * @param value the byte array value to be written 741 * @param offset the initial offset within the byte array 742 * @param length the number of bytes to use 743 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 744 * @throws MessageNotWriteableException if the message is in read-only mode. 745 */ 746 public void writeBytes(byte[] value, int offset, int length) throws JMSException { 747 initializeWriting(); 748 try { 749 this.dataOut.write(value, offset, length); 750 } 751 catch (IOException ioe) { 752 JMSException jmsEx = new JMSException("Could not write data:" + ioe.getMessage()); 753 jmsEx.setLinkedException(ioe); 754 throw jmsEx; 755 } 756 } 757 758 /** 759 * Writes an object to the bytes message stream. 760 * <P> 761 * This method works only for the objectified primitive object types (<code>Integer</code>,<code>Double</code>, 762 * <code>Long</code> ...), <code>String</code> objects, and byte arrays. 763 * 764 * @param value the object in the Java programming language ("Java object") to be written; it must not be null 765 * @throws JMSException if the JMS provider fails to write the message due to some internal error. 766 * @throws MessageFormatException if the object is of an invalid type. 767 * @throws MessageNotWriteableException if the message is in read-only mode. 768 * @throws java.lang.NullPointerException if the parameter <code>value</code> is null. 769 */ 770 public void writeObject(Object value) throws JMSException { 771 if (value == null) { 772 throw new NullPointerException(); 773 } 774 initializeWriting(); 775 if (value instanceof Boolean) { 776 writeBoolean(((Boolean) value).booleanValue()); 777 } 778 else if (value instanceof Character) { 779 writeChar(((Character) value).charValue()); 780 } 781 else if (value instanceof Byte) { 782 writeByte(((Byte) value).byteValue()); 783 } 784 else if (value instanceof Short) { 785 writeShort(((Short) value).shortValue()); 786 } 787 else if (value instanceof Integer) { 788 writeInt(((Integer) value).intValue()); 789 } 790 else if (value instanceof Double) { 791 writeDouble(((Double) value).doubleValue()); 792 } 793 else if (value instanceof Long) { 794 writeLong(((Long) value).longValue()); 795 } 796 else if (value instanceof Float) { 797 writeFloat(((Float) value).floatValue()); 798 } 799 else if (value instanceof Double) { 800 writeDouble(((Double) value).doubleValue()); 801 } 802 else if (value instanceof String) { 803 writeUTF(value.toString()); 804 } 805 else if (value instanceof byte[]) { 806 writeBytes((byte[]) value); 807 } 808 else { 809 throw new MessageFormatException("Cannot write non-primitive type:" + value.getClass()); 810 } 811 } 812 813 /** 814 * Puts the message body in read-only mode and repositions the stream of bytes to the beginning. 815 * 816 * @throws JMSException if an internal error occurs 817 */ 818 public void reset() throws JMSException { 819 super.readOnlyMessage = true; 820 if (this.dataOut != null) { 821 try { 822 this.dataOut.flush(); 823 byte[] data = this.bytesOut.toByteArray(); 824 super.setBodyAsBytes(data,0,data.length); 825 dataOut.close(); 826 } 827 catch (IOException ioe) { 828 JMSException jmsEx = new JMSException("reset failed: " + ioe.getMessage()); 829 jmsEx.setLinkedException(ioe); 830 throw jmsEx; 831 } 832 } 833 this.bytesOut = null; 834 this.dataIn = null; 835 this.dataOut = null; 836 } 837 838 private void initializeWriting() throws MessageNotWriteableException { 839 if (super.readOnlyMessage) { 840 throw new MessageNotWriteableException("This message is in read-only mode"); 841 } 842 if (this.dataOut == null) { 843 this.bytesOut = new ByteArrayOutputStream(); 844 this.dataOut = new DataOutputStream(this.bytesOut); 845 } 846 } 847 848 private void initializeReading() throws MessageNotReadableException { 849 if (!super.readOnlyMessage) { 850 throw new MessageNotReadableException("This message is in write-only mode"); 851 } 852 try { 853 ByteArray data = super.getBodyAsBytes(); 854 if (this.dataIn == null && data != null) { 855 if (ByteArrayCompression.isCompressed(data)){ 856 ByteArrayCompression compression = new ByteArrayCompression(); 857 data = compression.inflate(data); 858 } 859 this.bodyLength = data.getLength(); 860 ByteArrayInputStream bytesIn = new ByteArrayInputStream(data.getBuf(),data.getOffset(),data.getLength()); 861 this.dataIn = new DataInputStream(bytesIn); 862 } 863 } 864 catch (IOException e) { 865 MessageNotReadableException mnr = new MessageNotReadableException("getBodyAsBytes failed"); 866 mnr.setLinkedException(e); 867 throw mnr; 868 } 869 } 870 871 public String toString() { 872 return super.toString() + " ActiveMQBytesMessage{ " + 873 "bytesOut = " + bytesOut + 874 ", dataOut = " + dataOut + 875 ", dataIn = " + dataIn + 876 " }"; 877 } 878 }