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 }