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