View Javadoc

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> &nbsp;...), <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 }