1 /***
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright
7 * statements and notices. Redistributions must also contain a
8 * copy of this document.
9 *
10 * 2. Redistributions in binary form must reproduce the
11 * above copyright notice, this list of conditions and the
12 * following disclaimer in the documentation and/or other
13 * materials provided with the distribution.
14 *
15 * 3. The name "Exolab" must not be used to endorse or promote
16 * products derived from this Software without prior written
17 * permission of Exoffice Technologies. For written permission,
18 * please contact info@exolab.org.
19 *
20 * 4. Products derived from this Software may not be called "Exolab"
21 * nor may "Exolab" appear in their names without prior written
22 * permission of Exoffice Technologies. Exolab is a registered
23 * trademark of Exoffice Technologies.
24 *
25 * 5. Due credit should be given to the Exolab Project
26 * (http://www.exolab.org/).
27 *
28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Copyright 2000-2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: BytesMessageImpl.java,v 1.2 2005/03/18 03:50:12 tanderson Exp $
44 */
45 package org.exolab.jms.message;
46
47 import java.io.ByteArrayInputStream;
48 import java.io.ByteArrayOutputStream;
49 import java.io.DataInputStream;
50 import java.io.DataOutputStream;
51 import java.io.EOFException;
52 import java.io.IOException;
53 import java.io.ObjectInput;
54 import java.io.ObjectOutput;
55 import java.io.UTFDataFormatException;
56
57 import javax.jms.BytesMessage;
58 import javax.jms.JMSException;
59 import javax.jms.MessageEOFException;
60 import javax.jms.MessageFormatException;
61 import javax.jms.MessageNotReadableException;
62 import javax.jms.MessageNotWriteableException;
63
64
65 /***
66 * This class implements the {@link BytesMessage} interface.
67 *
68 * @version $Revision: 1.2 $ $Date: 2005/03/18 03:50:12 $
69 * @author <a href="mailto:mourikis@intalio.com">Jim Mourikis</a>
70 * @author <a href="mailto:tima@netspace.net.au">Tim Anderson</a>
71 * @see BytesMessage
72 */
73 public final class BytesMessageImpl extends MessageImpl
74 implements BytesMessage {
75
76 /***
77 * Object version no. for serialization.
78 */
79 static final long serialVersionUID = 1;
80
81 /***
82 * Empty byte array for initialisation purposes.
83 */
84 private static final byte[] EMPTY = new byte[]{};
85
86 /***
87 * The byte stream to store data.
88 */
89 private byte[] _bytes = EMPTY;
90
91 /***
92 * The stream used for writes.
93 */
94 private DataOutputStream _out = null;
95
96 /***
97 * The byte stream backing the output stream.
98 */
99 private ByteArrayOutputStream _byteOut = null;
100
101 /***
102 * The stream used for reads.
103 */
104 private DataInputStream _in = null;
105
106 /***
107 * The byte stream backing the input stream.
108 */
109 private ByteArrayInputStream _byteIn = null;
110
111 /***
112 * The offset of the byte stream to start reading from. This defaults
113 * to 0, and only applies to messages that are cloned from a
114 * read-only instance where part of the stream had already been read.
115 */
116 private int _offset = 0;
117
118 /***
119 * Construct a new BytesMessage. When first created, the message is in
120 * write-only mode.
121 *
122 * @throws JMSException if the message type can't be set
123 */
124 public BytesMessageImpl() throws JMSException {
125 setJMSType("BytesMessage");
126 }
127
128 /***
129 * Clone an instance of this object.
130 *
131 * @return a copy of this object
132 * @throws CloneNotSupportedException if object or attributes aren't
133 * cloneable
134 */
135 public final Object clone() throws CloneNotSupportedException {
136 BytesMessageImpl result = (BytesMessageImpl) super.clone();
137 if (_bodyReadOnly) {
138 result._bytes = new byte[_bytes.length];
139 System.arraycopy(_bytes, 0, result._bytes, 0, _bytes.length);
140 if (_byteIn != null) {
141
142
143 _offset = _bytes.length - _byteIn.available();
144 }
145 result._byteIn = null;
146 result._in = null;
147 } else {
148 if (_out != null) {
149 try {
150 _out.flush();
151 } catch (IOException exception) {
152 throw new CloneNotSupportedException(
153 exception.getMessage());
154 }
155 result._bytes = _byteOut.toByteArray();
156 result._byteOut = null;
157 result._out = null;
158 } else {
159 result._bytes = new byte[_bytes.length];
160 System.arraycopy(_bytes, 0, result._bytes, 0, _bytes.length);
161 }
162 }
163
164 return result;
165 }
166
167 /***
168 * Serialize out this message's data.
169 *
170 * @param out the stream to serialize out to
171 * @throws IOException if any I/O exceptions occurr
172 */
173 public final void writeExternal(ObjectOutput out) throws IOException {
174
175 if (!_bodyReadOnly && _out != null) {
176 _out.flush();
177 _bytes = _byteOut.toByteArray();
178 }
179
180 super.writeExternal(out);
181 out.writeLong(serialVersionUID);
182 out.writeInt(_bytes.length);
183 out.write(_bytes);
184 out.flush();
185 }
186
187 /***
188 * Serialize in this message's data.
189 *
190 * @param in the stream to serialize in from
191 * @throws ClassNotFoundException if the class for an object being
192 * restored cannot be found.
193 * @throws IOException if any I/O exceptions occur
194 */
195 public final void readExternal(ObjectInput in)
196 throws ClassNotFoundException, IOException {
197 super.readExternal(in);
198 long version = in.readLong();
199 if (version == serialVersionUID) {
200 int length = in.readInt();
201 _bytes = new byte[length];
202 in.readFully(_bytes);
203 } else {
204 throw new IOException("Incorrect version enountered: " + version +
205 ". This version = " + serialVersionUID);
206 }
207 }
208
209 /***
210 * Gets the number of bytes of the message body when the message is in
211 * read-only mode. The value returned can be used to allocate a byte array.
212 * The value returned is the entire length of the message body, regardless
213 * of where the pointer for reading the message is currently located.
214 *
215 * @return number of bytes in the message
216 * @throws JMSException if the JMS provider fails to read the
217 * message due to some internal error.
218 * @throws MessageNotReadableException if the message is in write-only
219 * mode.
220 */
221
222 public long getBodyLength() throws JMSException {
223 checkRead();
224 return _bytes.length;
225 }
226
227 /***
228 * Read a <code>boolean</code> from the bytes message stream.
229 *
230 * @return the <code>boolean</code> value read
231 * @throws JMSException if JMS fails to read message due to some internal
232 * JMS error
233 * @throws MessageEOFException if end of bytes stream
234 * @throws MessageNotReadableException if message is in write-only mode
235 */
236 public final boolean readBoolean() throws JMSException {
237 boolean result = false;
238 prepare();
239 try {
240 result = _in.readBoolean();
241 } catch (IOException exception) {
242 revert(exception);
243 }
244 return result;
245 }
246
247 /***
248 * Read a signed 8-bit value from the bytes message stream.
249 *
250 * @return the next byte from the bytes message stream as a signed 8-bit
251 * <code>byte</code>
252 * @throws JMSException if JMS fails to read message due to some internal
253 * JMS error
254 * @throws MessageEOFException if end of message stream
255 * @throws MessageNotReadableException if message is in write-only mode
256 */
257 public final byte readByte() throws JMSException {
258 byte result = 0;
259 prepare();
260 try {
261 result = _in.readByte();
262 } catch (IOException exception) {
263 revert(exception);
264 }
265 return result;
266 }
267
268 /***
269 * Read an unsigned 8-bit number from the bytes message stream.
270 *
271 * @return the next byte from the bytes message stream, interpreted as an
272 * unsigned 8-bit number
273 * @throws JMSException if JMS fails to read message due to some internal
274 * JMS error
275 * @throws MessageNotReadableException if message is in write-only mode
276 * @throws MessageEOFException if end of message stream
277 */
278 public final int readUnsignedByte() throws JMSException {
279 int result = 0;
280 prepare();
281 try {
282 result = _in.readUnsignedByte();
283 } catch (IOException exception) {
284 revert(exception);
285 }
286 return result;
287 }
288
289 /***
290 * Read a signed 16-bit number from the bytes message stream.
291 *
292 * @return the next two bytes from the bytes message stream, interpreted
293 * as a signed 16-bit number
294 * @throws JMSException if JMS fails to read message due to some internal
295 * JMS error
296 * @throws MessageEOFException if end of message stream
297 * @throws MessageNotReadableException if message is in write-only mode
298 */
299 public final short readShort() throws JMSException {
300 short result = 0;
301 prepare();
302 try {
303 result = _in.readShort();
304 } catch (IOException exception) {
305 revert(exception);
306 }
307 return result;
308 }
309
310 /***
311 * Read an unsigned 16-bit number from the bytes message stream.
312 *
313 * @return the next two bytes from the bytes message stream, interpreted
314 * as an unsigned 16-bit integer
315 *
316 * @throws JMSException if JMS fails to read message due to some internal
317 * JMS error
318 * @throws MessageEOFException if end of message stream
319 * @throws MessageNotReadableException if message is in write-only mode
320 */
321 public final int readUnsignedShort() throws JMSException {
322 int result = 0;
323 prepare();
324 try {
325 result = _in.readUnsignedShort();
326 } catch (IOException exception) {
327 revert(exception);
328 }
329 return result;
330 }
331
332 /***
333 * Read a Unicode character value from the bytes message stream.
334 *
335 * @return the next two bytes from the bytes message stream as a Unicode
336 * character
337 * @throws JMSException if JMS fails to read message due to some internal
338 * JMS error
339 * @throws MessageEOFException if end of message stream
340 * @throws MessageNotReadableException if message is in write-only mode
341 */
342 public final char readChar() throws JMSException {
343 char result = 0;
344 prepare();
345 try {
346 result = _in.readChar();
347 } catch (IOException exception) {
348 revert(exception);
349 }
350 return result;
351 }
352
353 /***
354 * Read a signed 32-bit integer from the bytes message stream.
355 *
356 * @return the next four bytes from the bytes message stream, interpreted
357 * as an <code>int</code>
358 * @throws JMSException if JMS fails to read message due to some internal
359 * JMS error
360 * @throws MessageEOFException if end of message stream
361 * @throws MessageNotReadableException if message is in write-only mode
362 */
363 public final int readInt() throws JMSException {
364 int result = 0;
365 prepare();
366 try {
367 result = _in.readInt();
368 } catch (IOException exception) {
369 revert(exception);
370 }
371 return result;
372 }
373
374 /***
375 * Read a signed 64-bit integer from the bytes message stream.
376 *
377 * @return the next eight bytes from the bytes message stream, interpreted
378 * as a <code>long</code>.
379 * @throws JMSException if JMS fails to read message due to some internal
380 * JMS error
381 * @throws MessageEOFException if end of message stream
382 * @throws MessageNotReadableException if message is in write-only mode
383 */
384 public final long readLong() throws JMSException {
385 long result = 0;
386 prepare();
387 try {
388 result = _in.readLong();
389 } catch (IOException exception) {
390 revert(exception);
391 }
392 return result;
393 }
394
395 /***
396 * Read a <code>float</code> from the bytes message stream.
397 *
398 * @return the next four bytes from the bytes message stream, interpreted
399 * as a <code>float</code>
400 * @throws JMSException if JMS fails to read message due to some internal
401 * JMS error
402 * @throws MessageEOFException if end of message stream
403 * @throws MessageNotReadableException if message is in write-only mode
404 */
405 public final float readFloat() throws JMSException {
406 float result = 0;
407 prepare();
408 try {
409 result = _in.readFloat();
410 } catch (IOException exception) {
411 revert(exception);
412 }
413 return result;
414 }
415
416 /***
417 * Read a <code>double</code> from the bytes message stream.
418 *
419 * @return the next eight bytes from the bytes message stream,
420 * interpreted as a <code>double</code>
421 * @throws JMSException if JMS fails to read message due to some internal
422 * JMS error
423 * @throws MessageEOFException if end of message stream
424 * @throws MessageNotReadableException if message is in write-only mode
425 */
426 public final double readDouble() throws JMSException {
427 double result = 0;
428 prepare();
429 try {
430 result = _in.readDouble();
431 } catch (IOException exception) {
432 revert(exception);
433 }
434 return result;
435 }
436
437 /***
438 * Read in a string that has been encoded using a modified UTF-8 format
439 * from the bytes message stream.
440 *
441 * <p>For more information on the UTF-8 format, see "File System Safe
442 * UCS Transformation Format (FSS_UFT)", X/Open Preliminary Specification,
443 * X/Open Company Ltd., Document Number: P316. This information also
444 * appears in ISO/IEC 10646, Annex P.
445 *
446 * @return a Unicode string from the bytes message stream
447 * @throws JMSException if JMS fails to read message due to some internal
448 * JMS error
449 * @throws MessageEOFException if end of message stream
450 * @throws MessageFormatException if string has an invalid format
451 * @throws MessageNotReadableException if message is in write-only mode
452 */
453 public final String readUTF() throws JMSException {
454 String result = null;
455 prepare();
456 try {
457 result = _in.readUTF();
458 } catch (IOException exception) {
459 revert(exception);
460 }
461 return result;
462 }
463
464 /***
465 * Read a byte array from the bytes message stream.
466 *
467 * <p>If the length of array <code>value</code> is less than
468 * the bytes remaining to be read from the stream, the array should
469 * be filled. A subsequent call reads the next increment, etc.
470 *
471 * <p>If the bytes remaining in the stream is less than the length of
472 * array <code>value</code>, the bytes should be read into the array.
473 * The return value of the total number of bytes read will be less than
474 * the length of the array, indicating that there are no more bytes left
475 * to be read from the stream. The next read of the stream returns -1.
476 *
477 * @param value the buffer into which the data is read
478 * @return the total number of bytes read into the buffer, or -1 if
479 * there is no more data because the end of the stream has been reached
480 * @throws JMSException if JMS fails to read message due to some internal
481 * JMS error
482 * @throws MessageNotReadableException if message is in write-only mode
483 */
484 public final int readBytes(byte[] value) throws JMSException {
485 return readBytes(value, value.length);
486 }
487
488 /***
489 * Read a portion of the bytes message stream.
490 *
491 * <p>If the length of array <code>value</code> is less than
492 * the bytes remaining to be read from the stream, the array should
493 * be filled. A subsequent call reads the next increment, etc.
494 *
495 * <p>If the bytes remaining in the stream is less than the length of
496 * array <code>value</code>, the bytes should be read into the array.
497 * The return value of the total number of bytes read will be less than
498 * the length of the array, indicating that there are no more bytes left
499 * to be read from the stream. The next read of the stream returns -1.
500 *
501 * <p> If <code>length</code> is negative, or
502 * <code>length</code> is greater than the length of the array
503 * <code>value</code>, then an <code>IndexOutOfBoundsException</code> is
504 * thrown. No bytes will be read from the stream for this exception case.
505 *
506 * @param value the buffer into which the data is read.
507 * @param length the number of bytes to read. Must be less than or equal
508 * to value.length.
509 * @return the total number of bytes read into the buffer, or -1 if
510 * there is no more data because the end of the stream has been reached.
511 * @throws IndexOutOfBoundsException if <code>length</code> is invalid
512 * @throws JMSException if JMS fails to read message due to some internal
513 * JMS error
514 * @throws MessageNotReadableException if message is in write-only mode
515 */
516 public final int readBytes(byte[] value, int length) throws JMSException {
517 int read = -1;
518 prepare();
519
520 if (length < 0 || length > value.length) {
521 throw new IndexOutOfBoundsException(
522 "Length must be > 0 and less than array size");
523 }
524 try {
525 _in.mark(length);
526 int remain = _in.available();
527 if (remain == 0) {
528 read = -1;
529 } else if (length <= remain) {
530 read = length;
531 _in.read(value, 0, length);
532 } else {
533 _in.readFully(value, 0, remain);
534 read = remain;
535 }
536 } catch (EOFException ignore) {
537 } catch (IOException exception) {
538 revert(exception);
539 }
540 return read;
541 }
542
543 /***
544 * Write a <code>boolean</code> to the bytes message stream as a 1-byte
545 * value.
546 * The value <code>true</code> is written out as the value
547 * <code>(byte)1</code>; the value <code>false</code> is written out as
548 * the value <code>(byte)0</code>.
549 *
550 * @param value the <code>boolean</code> value to be written
551 * @throws JMSException if JMS fails to write message due to some internal
552 * JMS error
553 * @throws MessageNotWriteableException if message is in read-only mode
554 */
555 public final void writeBoolean(boolean value) throws JMSException {
556 checkWrite();
557 try {
558 getOutputStream().writeBoolean(value);
559 } catch (IOException exception) {
560 raise(exception);
561 }
562 }
563
564 /***
565 * Write out a <code>byte</code> to the bytes message stream as a 1-byte
566 * value.
567 *
568 * @param value the <code>byte</code> value to be written
569 * @throws JMSException if JMS fails to write message due to some internal
570 * JMS error
571 * @throws MessageNotWriteableException if message is in read-only mode
572 */
573 public final void writeByte(byte value) throws JMSException {
574 checkWrite();
575 try {
576 getOutputStream().writeByte(value);
577 } catch (IOException exception) {
578 raise(exception);
579 }
580 }
581
582 /***
583 * Write a <code>short</code> to the bytes message stream as two bytes,
584 * high byte first.
585 *
586 * @param value the <code>short</code> to be written
587 * @throws JMSException if JMS fails to write message due to some internal
588 * JMS error
589 * @throws MessageNotWriteableException if message is in read-only mode
590 */
591 public final void writeShort(short value) throws JMSException {
592 checkWrite();
593 try {
594 getOutputStream().writeShort(value);
595 } catch (IOException exception) {
596 raise(exception);
597 }
598 }
599
600 /***
601 * Write a <code>char</code> to the bytes message stream as a 2-byte
602 * value, high byte first.
603 *
604 * @param value the <code>char</code> value to be written
605 * @throws MessageNotWriteableException if message is in read-only mode
606 * @throws JMSException if JMS fails to write message due to some internal
607 * JMS error
608 */
609 public final void writeChar(char value) throws JMSException {
610 checkWrite();
611 try {
612 getOutputStream().writeChar(value);
613 } catch (IOException exception) {
614 raise(exception);
615 }
616 }
617
618 /***
619 * Write an <code>int</code> to the bytes message stream as four bytes,
620 * high byte first.
621 *
622 * @param value the <code>int</code> to be written
623 * @throws JMSException if JMS fails to write message due to some internal
624 * JMS error
625 * @throws MessageNotWriteableException if message is in read-only mode
626 */
627 public final void writeInt(int value) throws JMSException {
628 checkWrite();
629 try {
630 getOutputStream().writeInt(value);
631 } catch (IOException exception) {
632 raise(exception);
633 }
634 }
635
636 /***
637 * Write a <code>long</code> to the bytes message stream as eight bytes,
638 * high byte first
639 *
640 * @param value the <code>long</code> to be written
641 * @throws JMSException if JMS fails to write message due to some internal
642 * JMS error
643 * @throws MessageNotWriteableException if message is in read-only mode
644 */
645 public final void writeLong(long value) throws JMSException {
646 checkWrite();
647 try {
648 getOutputStream().writeLong(value);
649 } catch (IOException exception) {
650 raise(exception);
651 }
652 }
653
654 /***
655 * Convert the float argument to an <code>int</code> using the
656 * <code>floatToIntBits</code> method in class <code>Float</code>,
657 * and then writes that <code>int</code> value to the bytes message
658 * stream as a 4-byte quantity, high byte first.
659 *
660 * @param value the <code>float</code> value to be written.
661 * @throws JMSException if JMS fails to write message due to some internal
662 * JMS error
663 * @throws MessageNotWriteableException if message is in read-only mode
664 */
665 public final void writeFloat(float value) throws JMSException {
666 checkWrite();
667 try {
668 getOutputStream().writeFloat(value);
669 } catch (IOException exception) {
670 raise(exception);
671 }
672 }
673
674
675 /***
676 * Convert the double argument to a <code>long</code> using the
677 * <code>doubleToLongBits</code> method in class <code>Double</code>,
678 * and then writes that <code>long</code> value to the bytes message
679 * stream as an 8-byte quantity, high byte first.
680 *
681 * @param value the <code>double</code> value to be written.
682 * @throws JMSException if JMS fails to write message due to some internal
683 * JMS error
684 * @throws MessageNotWriteableException if message is in read-only mode
685 */
686 public final void writeDouble(double value) throws JMSException {
687 checkWrite();
688 try {
689 getOutputStream().writeDouble(value);
690 } catch (IOException exception) {
691 raise(exception);
692 }
693 }
694
695 /***
696 * Write a string to the bytes message stream using UTF-8 encoding in a
697 * machine-independent manner.
698 *
699 * <p>For more information on the UTF-8 format, see "File System Safe
700 * UCS Transformation Format (FSS_UFT)", X/Open Preliminary Specification,
701 * X/Open Company Ltd., Document Number: P316. This information also
702 * appears in ISO/IEC 10646, Annex P.
703 *
704 * @param value the <code>String</code> value to be written
705 * @throws MessageNotWriteableException if message is in read-only mode
706 * @throws JMSException if JMS fails to write message due to some internal
707 * JMS error
708 */
709 public final void writeUTF(String value) throws JMSException {
710 checkWrite();
711 try {
712 getOutputStream().writeUTF(value);
713 } catch (IOException exception) {
714 raise(exception);
715 }
716 }
717
718 /***
719 * Write a byte array to the bytes message stream.
720 *
721 * @param value the byte array to be written.
722 * @throws JMSException if JMS fails to write message due to some internal
723 * JMS error
724 * @throws MessageNotWriteableException if message is in read-only mode
725 */
726 public final void writeBytes(byte[] value) throws JMSException {
727 checkWrite();
728 try {
729 getOutputStream().write(value);
730 } catch (IOException exception) {
731 raise(exception);
732 }
733 }
734
735 /***
736 * Write a portion of a byte array to the bytes message stream
737 *
738 * @param value the byte array value to be written.
739 * @param offset the initial offset within the byte array.
740 * @param length the number of bytes to use.
741 * @throws JMSException if JMS fails to write message due to some internal
742 * JMS error
743 * @throws MessageNotWriteableException if message is in read-only mode
744 */
745 public final void writeBytes(byte[] value, int offset, int length)
746 throws JMSException {
747 checkWrite();
748 try {
749 getOutputStream().write(value, offset, length);
750 } catch (IOException exception) {
751 raise(exception);
752 }
753 }
754
755 /***
756 * Write a Java object to the bytes message stream.
757 *
758 * <p>Note that this method only works for the objectified primitive
759 * object types (Integer, Double, Long ...), String's and byte arrays.
760 *
761 * @param value the Java object to be written. Must not be null.
762 *
763 * @throws JMSException if JMS fails to write message due to some internal
764 * JMS error
765 * @throws MessageFormatException if object is invalid type
766 * @throws MessageNotWriteableException if message in read-only mode
767 * @throws NullPointerException if parameter <code>value</code> is null
768 */
769 public final void writeObject(Object value) throws JMSException {
770 if (value instanceof Boolean) {
771 writeBoolean(((Boolean) value).booleanValue());
772 } else if (value instanceof Byte) {
773 writeByte(((Byte) value).byteValue());
774 } else if (value instanceof Short) {
775 writeShort(((Short) value).shortValue());
776 } else if (value instanceof Character) {
777 writeChar(((Character) value).charValue());
778 } else if (value instanceof Integer) {
779 writeInt(((Integer) value).intValue());
780 } else if (value instanceof Long) {
781 writeLong(((Long) value).longValue());
782 } else if (value instanceof Float) {
783 writeFloat(((Float) value).floatValue());
784 } else if (value instanceof Double) {
785 writeDouble(((Double) value).doubleValue());
786 } else if (value instanceof String) {
787 writeUTF((String) value);
788 } else if (value instanceof byte[]) {
789 writeBytes((byte[]) value);
790 } else if (value == null) {
791 throw new NullPointerException(
792 "BytesMessage does not support null");
793 } else {
794 throw new MessageFormatException("Cannot write objects of type=" +
795 value.getClass().getName());
796 }
797 }
798
799 /***
800 * Put the message body in read-only mode, and reposition the stream of
801 * bytes to the beginning.
802 *
803 * @throws JMSException if JMS fails to reset the message due to some
804 * internal JMS error
805 */
806 public final void reset() throws JMSException {
807 try {
808 if (!_bodyReadOnly) {
809 _bodyReadOnly = true;
810 if (_out != null) {
811 _out.flush();
812 _bytes = _byteOut.toByteArray();
813 _byteOut = null;
814 _out.close();
815 _out = null;
816 }
817 } else {
818 if (_in != null) {
819 _byteIn = null;
820 _in.close();
821 _in = null;
822 }
823 }
824 } catch (IOException exception) {
825 raise(exception);
826 }
827 }
828
829 /***
830 * Overide the super class method to reset the streams, and put the
831 * message body in write only mode.
832 *
833 * <p>If <code>clearBody</code> is called on a message in read-only mode,
834 * the message body is cleared and the message is in write-only mode.
835 * bytes to the beginning.
836 *
837 * <p>If <code>clearBody</code> is called on a message already in
838 * write-only mode, the spec does not define the outcome, so do nothing.
839 * Client must then call <code>reset</code>, followed by
840 * <code>clearBody</code> to reset the stream at the beginning for a
841 * new write.
842 * @throws JMSException if JMS fails to reset the message due to some
843 * internal JMS error
844 */
845 public final void clearBody() throws JMSException {
846 try {
847 if (_bodyReadOnly) {
848
849 _bodyReadOnly = false;
850 if (_in != null) {
851 _byteIn = null;
852 _in.close();
853 _in = null;
854 _offset = 0;
855 }
856 } else if (_out != null) {
857
858 _byteOut = null;
859 _out.close();
860 _out = null;
861 }
862 _bytes = EMPTY;
863 _byteOut = null;
864 _out = null;
865 } catch (IOException exception) {
866 raise(exception);
867 }
868 }
869
870 /***
871 * Set the read-only mode of the message.
872 *
873 * @param readOnly if true, make the message body and properties read-only,
874 * and invoke {@link #reset}
875 * @throws JMSException if the read-only mode cannot be changed
876 */
877 public final void setReadOnly(boolean readOnly) throws JMSException {
878 if (readOnly) {
879 reset();
880 }
881 super.setReadOnly(readOnly);
882 }
883
884 /***
885 * Prepare to do a read.
886 *
887 * @throws JMSException if the current position in the stream can't be
888 * marked
889 * @throws MessageNotReadableException if the message is in write-only mode
890 */
891 private final void prepare() throws JMSException {
892 checkRead();
893 getInputStream();
894 try {
895 _in.mark(_bytes.length - _in.available());
896 } catch (IOException exception) {
897 raise(exception);
898 }
899 }
900
901 /***
902 * Reverts the stream to its prior position if an I/O exception is
903 * thrown, and propagates the exception as a JMSException.
904 *
905 * @param exception the exception that caused the reset
906 * @throws JMSException for general IOException errors
907 * @throws MessageEOFException if end-of-file was reached
908 */
909 private final void revert(IOException exception) throws JMSException {
910 try {
911 _in.reset();
912 } catch (IOException ignore) {
913 }
914 JMSException error = null;
915 if (exception instanceof EOFException) {
916 error = new MessageEOFException(exception.getMessage());
917 } else if (exception instanceof UTFDataFormatException) {
918 error = new MessageFormatException(exception.getMessage());
919 } else {
920 error = new JMSException(exception.getMessage());
921 }
922 error.setLinkedException(exception);
923 throw error;
924 }
925
926 /***
927 * Initialise the input stream if it hasn't been intialised.
928 *
929 * @return the input stream
930 */
931 private DataInputStream getInputStream() {
932 if (_in == null) {
933 _byteIn = new ByteArrayInputStream(_bytes, _offset,
934 _bytes.length - _offset);
935 _in = new DataInputStream(_byteIn);
936 }
937 return _in;
938 }
939
940 /***
941 * Initialise the output stream if it hasn't been intialised.
942 *
943 * @return the output stream
944 * @throws IOException if the output stream can't be created
945 */
946 private final DataOutputStream getOutputStream() throws IOException {
947 if (_out == null) {
948 _byteOut = new ByteArrayOutputStream();
949 _out = new DataOutputStream(_byteOut);
950 _out.write(_bytes);
951 }
952 return _out;
953 }
954
955 /***
956 * Helper to raise a JMSException when an I/O error occurs.
957 *
958 * @param exception the exception that caused the failure
959 * @throws JMSException
960 */
961 private final void raise(IOException exception) throws JMSException {
962 JMSException error = new JMSException(exception.getMessage());
963 error.setLinkedException(exception);
964 throw error;
965 }
966
967 }