Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/activemq/message/ActiveMQStreamMessage.java


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  
19  package org.activemq.message;
20  
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 javax.jms.StreamMessage;
27  
28  import org.activemq.io.util.ByteArray;
29  import org.activemq.io.util.ByteArrayCompression;
30  
31  import java.io.ByteArrayInputStream;
32  import java.io.ByteArrayOutputStream;
33  import java.io.DataInputStream;
34  import java.io.DataOutputStream;
35  import java.io.EOFException;
36  import java.io.IOException;
37  
38  /**
39   * A <CODE>StreamMessage</CODE> object is used to send a stream of primitive
40   * types in the Java programming language. It is filled and read sequentially.
41   * It inherits from the <CODE>Message</CODE> interface
42   * and adds a stream message body. Its methods are based largely on those
43   * found in <CODE>java.io.DataInputStream</CODE> and
44   * <CODE>java.io.DataOutputStream</CODE>.
45   * <p/>
46   * <P>The primitive types can be read or written explicitly using methods
47   * for each type. They may also be read or written generically as objects.
48   * For instance, a call to <CODE>StreamMessage.writeInt(6)</CODE> is
49   * equivalent to <CODE>StreamMessage.writeObject(new Integer(6))</CODE>.
50   * Both forms are provided, because the explicit form is convenient for
51   * static programming, and the object form is needed when types are not known
52   * at compile time.
53   * <p/>
54   * <P>When the message is first created, and when <CODE>clearBody</CODE>
55   * is called, the body of the message is in write-only mode. After the
56   * first call to <CODE>reset</CODE> has been made, the message body is in
57   * read-only mode.
58   * After a message has been sent, the client that sent it can retain and
59   * modify it without affecting the message that has been sent. The same message
60   * object can be sent multiple times.
61   * When a message has been received, the provider has called
62   * <CODE>reset</CODE> so that the message body is in read-only mode for the client.
63   * <p/>
64   * <P>If <CODE>clearBody</CODE> is called on a message in read-only mode,
65   * the message body is cleared and the message body is in write-only mode.
66   * <p/>
67   * <P>If a client attempts to read a message in write-only mode, a
68   * <CODE>MessageNotReadableException</CODE> is thrown.
69   * <p/>
70   * <P>If a client attempts to write a message in read-only mode, a
71   * <CODE>MessageNotWriteableException</CODE> is thrown.
72   * <p/>
73   * <P><CODE>StreamMessage</CODE> objects support the following conversion
74   * table. The marked cases must be supported. The unmarked cases must throw a
75   * <CODE>JMSException</CODE>. The <CODE>String</CODE>-to-primitive conversions
76   * may throw a runtime exception if the primitive's <CODE>valueOf()</CODE>
77   * method does not accept it as a valid <CODE>String</CODE> representation of
78   * the primitive.
79   * <p/>
80   * <P>A value written as the row type can be read as the column type.
81   * <p/>
82   * <PRE>
83   * |        | boolean byte short char int long float double String byte[]
84   * |----------------------------------------------------------------------
85   * |boolean |    X                                            X
86   * |byte    |          X     X         X   X                  X
87   * |short   |                X         X   X                  X
88   * |char    |                     X                           X
89   * |int     |                          X   X                  X
90   * |long    |                              X                  X
91   * |float   |                                    X     X      X
92   * |double  |                                          X      X
93   * |String  |    X     X     X         X   X     X     X      X
94   * |byte[]  |                                                        X
95   * |----------------------------------------------------------------------
96   * </PRE>
97   * <p/>
98   * <P>Attempting to read a null value as a primitive type must be treated
99   * as calling the primitive's corresponding <code>valueOf(String)</code>
100  * conversion method with a null value. Since <code>char</code> does not
101  * support a <code>String</code> conversion, attempting to read a null value
102  * as a <code>char</code> must throw a <code>NullPointerException</code>.
103  *
104  * @see javax.jms.Session#createStreamMessage()
105  * @see javax.jms.BytesMessage
106  * @see javax.jms.MapMessage
107  * @see javax.jms.Message
108  * @see javax.jms.ObjectMessage
109  * @see javax.jms.TextMessage
110  */
111 
112 public class ActiveMQStreamMessage extends ActiveMQMessage implements StreamMessage {
113 
114     private DataOutputStream dataOut;
115     private ByteArrayOutputStream bytesOut;
116     private DataInputStream dataIn;
117     private int bytesToRead = -1;
118 
119 
120     /**
121      * Return the type of Packet
122      *
123      * @return integer representation of the type of Packet
124      */
125 
126     public int getPacketType() {
127         return ACTIVEMQ_STREAM_MESSAGE;
128     }
129 
130     /**
131      * @return Returns a shallow copy of the message instance
132      * @throws JMSException
133      */
134 
135     public ActiveMQMessage shallowCopy() throws JMSException {
136         ActiveMQStreamMessage other = new ActiveMQStreamMessage();
137         this.initializeOther(other);
138         try {
139             other.setBodyAsBytes(this.getBodyAsBytes());
140         }
141         catch (IOException e) {
142             JMSException jmsEx = new JMSException("setBodyAsBytes() failed");
143             jmsEx.setLinkedException(e);
144             throw jmsEx;
145         }
146         return other;
147     }
148 
149     /**
150      * @return Returns a deep copy of the message - note the header fields are only shallow copied
151      * @throws JMSException
152      */
153 
154     public ActiveMQMessage deepCopy() throws JMSException {
155         ActiveMQStreamMessage other = new ActiveMQStreamMessage();
156         this.initializeOther(other);
157         try {
158             if (this.getBodyAsBytes() != null) {
159                 ByteArray data = this.getBodyAsBytes().copy();
160                 other.setBodyAsBytes(data);
161             }
162         }
163         catch (IOException e) {
164             JMSException jmsEx = new JMSException("setBodyAsBytes() failed");
165             jmsEx.setLinkedException(e);
166             throw jmsEx;
167         }
168         return other;
169     }
170 
171 
172     /**
173      * Clears out the message body. Clearing a message's body does not clear
174      * its header values or property entries.
175      * <p/>
176      * <P>If this message body was read-only, calling this method leaves
177      * the message body in the same state as an empty body in a newly
178      * created message.
179      *
180      * @throws JMSException if the JMS provider fails to clear the message
181      *                      body due to some internal error.
182      */
183 
184     public void clearBody() throws JMSException {
185         super.clearBody();
186         this.dataOut = null;
187         this.dataIn = null;
188         this.bytesOut = null;
189     }
190 
191     /**
192      * Reads a <code>boolean</code> from the stream message.
193      *
194      * @return the <code>boolean</code> value read
195      * @throws JMSException                if the JMS provider fails to read the message
196      *                                     due to some internal error.
197      * @throws MessageEOFException         if unexpected end of message stream has
198      *                                     been reached.
199      * @throws MessageFormatException      if this type conversion is invalid.
200      * @throws MessageNotReadableException if the message is in write-only
201      *                                     mode.
202      */
203 
204     public boolean readBoolean() throws JMSException {
205         initializeReading();
206         try {
207             if (this.dataIn.available() == 0) {
208                 throw new MessageEOFException("reached end of data");
209             }
210 
211             this.dataIn.mark(10);
212             int type = this.dataIn.read();
213             if (type == BOOLEAN) {
214                 return this.dataIn.readBoolean();
215             }
216             if (type == STRING) {
217                 return Boolean.valueOf(this.dataIn.readUTF()).booleanValue();
218             } 
219             if (type == NULL) {
220                 this.dataIn.reset();
221                 throw new NullPointerException("Cannot convert NULL value to boolean.");
222             }
223             else {
224                 this.dataIn.reset();
225                 throw new MessageFormatException(" not a boolean type");
226             }
227         }
228         catch (EOFException e) {
229             JMSException jmsEx = new MessageEOFException(e.getMessage());
230             jmsEx.setLinkedException(e);
231             throw jmsEx;
232         }
233         catch (IOException e) {
234             JMSException jmsEx = new MessageFormatException(e.getMessage());
235             jmsEx.setLinkedException(e);
236             throw jmsEx;
237         }
238     }
239 
240 
241     /**
242      * Reads a <code>byte</code> value from the stream message.
243      *
244      * @return the next byte from the stream message as a 8-bit
245      *         <code>byte</code>
246      * @throws JMSException                if the JMS provider fails to read the message
247      *                                     due to some internal error.
248      * @throws MessageEOFException         if unexpected end of message stream has
249      *                                     been reached.
250      * @throws MessageFormatException      if this type conversion is invalid.
251      * @throws MessageNotReadableException if the message is in write-only
252      *                                     mode.
253      */
254 
255     public byte readByte() throws JMSException {
256         initializeReading();
257         try {
258             if (this.dataIn.available() == 0) {
259                 throw new MessageEOFException("reached end of data");
260             }
261 
262             this.dataIn.mark(10);
263             int type = this.dataIn.read();
264             if (type == BYTE) {
265                 return this.dataIn.readByte();
266             }
267             if (type == STRING) {
268                 return Byte.valueOf(this.dataIn.readUTF()).byteValue();
269             } 
270             if (type == NULL) {
271                 this.dataIn.reset();
272                 throw new NullPointerException("Cannot convert NULL value to byte.");
273             }
274             else {
275                 this.dataIn.reset();
276                 throw new MessageFormatException(" not a byte type");
277             }
278         }
279         catch (NumberFormatException mfe) {
280             try {
281                 this.dataIn.reset();
282             }
283             catch (IOException ioe) {
284                 JMSException jmsEx = new JMSException("reset failed");
285                 jmsEx.setLinkedException(ioe);
286             }
287             throw mfe;
288 
289         }
290         catch (EOFException e) {
291             JMSException jmsEx = new MessageEOFException(e.getMessage());
292             jmsEx.setLinkedException(e);
293             throw jmsEx;
294         }
295         catch (IOException e) {
296             JMSException jmsEx = new MessageFormatException(e.getMessage());
297             jmsEx.setLinkedException(e);
298             throw jmsEx;
299         }
300     }
301 
302 
303     /**
304      * Reads a 16-bit integer from the stream message.
305      *
306      * @return a 16-bit integer from the stream message
307      * @throws JMSException                if the JMS provider fails to read the message
308      *                                     due to some internal error.
309      * @throws MessageEOFException         if unexpected end of message stream has
310      *                                     been reached.
311      * @throws MessageFormatException      if this type conversion is invalid.
312      * @throws MessageNotReadableException if the message is in write-only
313      *                                     mode.
314      */
315 
316     public short readShort() throws JMSException {
317         initializeReading();
318         try {
319             if (this.dataIn.available() == 0) {
320                 throw new MessageEOFException("reached end of data");
321             }
322 
323             this.dataIn.mark(17);
324             int type = this.dataIn.read();
325             if (type == SHORT) {
326                 return this.dataIn.readShort();
327             }
328             if (type == BYTE) {
329                 return this.dataIn.readByte();
330             }
331             if (type == STRING) {
332                 return Short.valueOf(this.dataIn.readUTF()).shortValue();
333             } 
334             if (type == NULL) {
335                 this.dataIn.reset();
336                 throw new NullPointerException("Cannot convert NULL value to short.");
337             }
338             else {
339                 this.dataIn.reset();
340                 throw new MessageFormatException(" not a short type");
341             }
342         }
343         catch (NumberFormatException mfe) {
344             try {
345                 this.dataIn.reset();
346             }
347             catch (IOException ioe) {
348                 JMSException jmsEx = new JMSException("reset failed");
349                 jmsEx.setLinkedException(ioe);
350             }
351             throw mfe;
352 
353         }
354         catch (EOFException e) {
355             JMSException jmsEx = new MessageEOFException(e.getMessage());
356             jmsEx.setLinkedException(e);
357             throw jmsEx;
358         }
359         catch (IOException e) {
360             JMSException jmsEx = new MessageFormatException(e.getMessage());
361             jmsEx.setLinkedException(e);
362             throw jmsEx;
363         }
364 
365     }
366 
367 
368     /**
369      * Reads a Unicode character value from the stream message.
370      *
371      * @return a Unicode character from the stream message
372      * @throws JMSException                if the JMS provider fails to read the message
373      *                                     due to some internal error.
374      * @throws MessageEOFException         if unexpected end of message stream has
375      *                                     been reached.
376      * @throws MessageFormatException      if this type conversion is invalid
377      * @throws MessageNotReadableException if the message is in write-only
378      *                                     mode.
379      */
380 
381     public char readChar() throws JMSException {
382         initializeReading();
383         try {
384             if (this.dataIn.available() == 0) {
385                 throw new MessageEOFException("reached end of data");
386             }
387 
388             this.dataIn.mark(17);
389             int type = this.dataIn.read();
390             if (type == CHAR) {
391                 return this.dataIn.readChar();
392             } 
393             if (type == NULL) {
394                 this.dataIn.reset();
395                 throw new NullPointerException("Cannot convert NULL value to char.");
396             } else {
397                 this.dataIn.reset();
398                 throw new MessageFormatException(" not a char type");
399             }
400         }
401         catch (NumberFormatException mfe) {
402             try {
403                 this.dataIn.reset();
404             }
405             catch (IOException ioe) {
406                 JMSException jmsEx = new JMSException("reset failed");
407                 jmsEx.setLinkedException(ioe);
408             }
409             throw mfe;
410 
411         }
412         catch (EOFException e) {
413             JMSException jmsEx = new MessageEOFException(e.getMessage());
414             jmsEx.setLinkedException(e);
415             throw jmsEx;
416         }
417         catch (IOException e) {
418             JMSException jmsEx = new MessageFormatException(e.getMessage());
419             jmsEx.setLinkedException(e);
420             throw jmsEx;
421         }
422     }
423 
424 
425     /**
426      * Reads a 32-bit integer from the stream message.
427      *
428      * @return a 32-bit integer value from the stream message, interpreted
429      *         as an <code>int</code>
430      * @throws JMSException                if the JMS provider fails to read the message
431      *                                     due to some internal error.
432      * @throws MessageEOFException         if unexpected end of message stream has
433      *                                     been reached.
434      * @throws MessageFormatException      if this type conversion is invalid.
435      * @throws MessageNotReadableException if the message is in write-only
436      *                                     mode.
437      */
438 
439     public int readInt() throws JMSException {
440         initializeReading();
441         try {
442             if (this.dataIn.available() == 0) {
443                 throw new MessageEOFException("reached end of data");
444             }
445 
446             this.dataIn.mark(33);
447             int type = this.dataIn.read();
448             if (type == INT) {
449                 return this.dataIn.readInt();
450             }
451             if (type == SHORT) {
452                 return this.dataIn.readShort();
453             }
454             if (type == BYTE) {
455                 return this.dataIn.readByte();
456             }
457             if (type == STRING) {
458                 return Integer.valueOf(this.dataIn.readUTF()).intValue();
459             } 
460             if (type == NULL) {
461                 this.dataIn.reset();
462                 throw new NullPointerException("Cannot convert NULL value to int.");
463             }
464             else {
465                 this.dataIn.reset();
466                 throw new MessageFormatException(" not an int type");
467             }
468         }
469         catch (NumberFormatException mfe) {
470             try {
471                 this.dataIn.reset();
472             }
473             catch (IOException ioe) {
474                 JMSException jmsEx = new JMSException("reset failed");
475                 jmsEx.setLinkedException(ioe);
476             }
477             throw mfe;
478 
479         }
480         catch (EOFException e) {
481             JMSException jmsEx = new MessageEOFException(e.getMessage());
482             jmsEx.setLinkedException(e);
483             throw jmsEx;
484         }
485         catch (IOException e) {
486             JMSException jmsEx = new MessageFormatException(e.getMessage());
487             jmsEx.setLinkedException(e);
488             throw jmsEx;
489         }
490     }
491 
492 
493     /**
494      * Reads a 64-bit integer from the stream message.
495      *
496      * @return a 64-bit integer value from the stream message, interpreted as
497      *         a <code>long</code>
498      * @throws JMSException                if the JMS provider fails to read the message
499      *                                     due to some internal error.
500      * @throws MessageEOFException         if unexpected end of message stream has
501      *                                     been reached.
502      * @throws MessageFormatException      if this type conversion is invalid.
503      * @throws MessageNotReadableException if the message is in write-only
504      *                                     mode.
505      */
506 
507     public long readLong() throws JMSException {
508         initializeReading();
509         try {
510             if (this.dataIn.available() == 0) {
511                 throw new MessageEOFException("reached end of data");
512             }
513 
514             this.dataIn.mark(65);
515             int type = this.dataIn.read();
516             if (type == LONG) {
517                 return this.dataIn.readLong();
518             }
519             if (type == INT) {
520                 return this.dataIn.readInt();
521             }
522             if (type == SHORT) {
523                 return this.dataIn.readShort();
524             }
525             if (type == BYTE) {
526                 return this.dataIn.readByte();
527             }
528             if (type == STRING) {
529                 return Long.valueOf(this.dataIn.readUTF()).longValue();
530             } 
531             if (type == NULL) {
532                 this.dataIn.reset();
533                 throw new NullPointerException("Cannot convert NULL value to long.");
534             }
535             else {
536                 this.dataIn.reset();
537                 throw new MessageFormatException(" not a long type");
538             }
539         }
540         catch (NumberFormatException mfe) {
541             try {
542                 this.dataIn.reset();
543             }
544             catch (IOException ioe) {
545                 JMSException jmsEx = new JMSException("reset failed");
546                 jmsEx.setLinkedException(ioe);
547             }
548             throw mfe;
549 
550         }
551         catch (EOFException e) {
552             JMSException jmsEx = new MessageEOFException(e.getMessage());
553             jmsEx.setLinkedException(e);
554             throw jmsEx;
555         }
556         catch (IOException e) {
557             JMSException jmsEx = new MessageFormatException(e.getMessage());
558             jmsEx.setLinkedException(e);
559             throw jmsEx;
560         }
561     }
562 
563 
564     /**
565      * Reads a <code>float</code> from the stream message.
566      *
567      * @return a <code>float</code> value from the stream message
568      * @throws JMSException                if the JMS provider fails to read the message
569      *                                     due to some internal error.
570      * @throws MessageEOFException         if unexpected end of message stream has
571      *                                     been reached.
572      * @throws MessageFormatException      if this type conversion is invalid.
573      * @throws MessageNotReadableException if the message is in write-only
574      *                                     mode.
575      */
576 
577     public float readFloat() throws JMSException {
578         initializeReading();
579         try {
580             if (this.dataIn.available() == 0) {
581                 throw new MessageEOFException("reached end of data");
582             }
583 
584             this.dataIn.mark(33);
585             int type = this.dataIn.read();
586             if (type == FLOAT) {
587                 return this.dataIn.readFloat();
588             }
589             if (type == STRING) {
590                 return Float.valueOf(this.dataIn.readUTF()).floatValue();
591             } 
592             if (type == NULL) {
593                 this.dataIn.reset();
594                 throw new NullPointerException("Cannot convert NULL value to float.");
595             }
596             else {
597                 this.dataIn.reset();
598                 throw new MessageFormatException(" not a float type");
599             }
600         }
601         catch (NumberFormatException mfe) {
602             try {
603                 this.dataIn.reset();
604             }
605             catch (IOException ioe) {
606                 JMSException jmsEx = new JMSException("reset failed");
607                 jmsEx.setLinkedException(ioe);
608             }
609             throw mfe;
610 
611         }
612         catch (EOFException e) {
613             JMSException jmsEx = new MessageEOFException(e.getMessage());
614             jmsEx.setLinkedException(e);
615             throw jmsEx;
616         }
617         catch (IOException e) {
618             JMSException jmsEx = new MessageFormatException(e.getMessage());
619             jmsEx.setLinkedException(e);
620             throw jmsEx;
621         }
622     }
623 
624 
625     /**
626      * Reads a <code>double</code> from the stream message.
627      *
628      * @return a <code>double</code> value from the stream message
629      * @throws JMSException                if the JMS provider fails to read the message
630      *                                     due to some internal error.
631      * @throws MessageEOFException         if unexpected end of message stream has
632      *                                     been reached.
633      * @throws MessageFormatException      if this type conversion is invalid.
634      * @throws MessageNotReadableException if the message is in write-only
635      *                                     mode.
636      */
637 
638     public double readDouble() throws JMSException {
639         initializeReading();
640         try {
641             if (this.dataIn.available() == 0) {
642                 throw new MessageEOFException("reached end of data");
643             }
644 
645             this.dataIn.mark(65);
646             int type = this.dataIn.read();
647             if (type == DOUBLE) {
648                 return this.dataIn.readDouble();
649             }
650             if (type == FLOAT) {
651                 return this.dataIn.readFloat();
652             }
653             if (type == STRING) {
654                 return Double.valueOf(this.dataIn.readUTF()).doubleValue();
655             } 
656             if (type == NULL) {
657                 this.dataIn.reset();
658                 throw new NullPointerException("Cannot convert NULL value to double.");
659             }
660             else {
661                 this.dataIn.reset();
662                 throw new MessageFormatException(" not a double type");
663             }
664         }
665         catch (NumberFormatException mfe) {
666             try {
667                 this.dataIn.reset();
668             }
669             catch (IOException ioe) {
670                 JMSException jmsEx = new JMSException("reset failed");
671                 jmsEx.setLinkedException(ioe);
672             }
673             throw mfe;
674 
675         }
676         catch (EOFException e) {
677             JMSException jmsEx = new MessageEOFException(e.getMessage());
678             jmsEx.setLinkedException(e);
679             throw jmsEx;
680         }
681         catch (IOException e) {
682             JMSException jmsEx = new MessageFormatException(e.getMessage());
683             jmsEx.setLinkedException(e);
684             throw jmsEx;
685         }
686     }
687 
688 
689     /**
690      * Reads a <CODE>String</CODE> from the stream message.
691      *
692      * @return a Unicode string from the stream message
693      * @throws JMSException                if the JMS provider fails to read the message
694      *                                     due to some internal error.
695      * @throws MessageEOFException         if unexpected end of message stream has
696      *                                     been reached.
697      * @throws MessageFormatException      if this type conversion is invalid.
698      * @throws MessageNotReadableException if the message is in write-only
699      *                                     mode.
700      */
701 
702     public String readString() throws JMSException {
703         initializeReading();
704         try {
705             if (this.dataIn.available() == 0) {
706                 throw new MessageEOFException("reached end of data");
707             }
708 
709             this.dataIn.mark(65);
710             int type = this.dataIn.read();
711             if (type == NULL) {
712                 return null;
713             }
714             if (type == STRING) {
715                 return this.dataIn.readUTF();
716             }
717             if (type == LONG) {
718                 return new Long(this.dataIn.readLong()).toString();
719             }
720             if (type == INT) {
721                 return new Integer(this.dataIn.readInt()).toString();
722             }
723             if (type == SHORT) {
724                 return new Short(this.dataIn.readShort()).toString();
725             }
726             if (type == BYTE) {
727                 return new Byte(this.dataIn.readByte()).toString();
728             }
729             if (type == FLOAT) {
730                 return new Float(this.dataIn.readFloat()).toString();
731             }
732             if (type == DOUBLE) {
733                 return new Double(this.dataIn.readDouble()).toString();
734             }
735             if (type == BOOLEAN) {
736                 return (this.dataIn.readBoolean() ? Boolean.TRUE : Boolean.FALSE).toString();
737             }
738             if (type == CHAR) {
739                 return new Character(this.dataIn.readChar()).toString();
740             }
741             else {
742                 this.dataIn.reset();
743                 throw new MessageFormatException(" not a String type");
744             }
745         }
746         catch (NumberFormatException mfe) {
747             try {
748                 this.dataIn.reset();
749             }
750             catch (IOException ioe) {
751                 JMSException jmsEx = new JMSException("reset failed");
752                 jmsEx.setLinkedException(ioe);
753             }
754             throw mfe;
755 
756         }
757         catch (EOFException e) {
758             JMSException jmsEx = new MessageEOFException(e.getMessage());
759             jmsEx.setLinkedException(e);
760             throw jmsEx;
761         }
762         catch (IOException e) {
763             JMSException jmsEx = new MessageFormatException(e.getMessage());
764             jmsEx.setLinkedException(e);
765             throw jmsEx;
766         }
767     }
768 
769 
770     /**
771      * Reads a byte array field from the stream message into the
772      * specified <CODE>byte[]</CODE> object (the read buffer).
773      * <p/>
774      * <P>To read the field value, <CODE>readBytes</CODE> should be
775      * successively called
776      * until it returns a value less than the length of the read buffer.
777      * The value of the bytes in the buffer following the last byte
778      * read is undefined.
779      * <p/>
780      * <P>If <CODE>readBytes</CODE> returns a value equal to the length of the
781      * buffer, a subsequent <CODE>readBytes</CODE> call must be made. If there
782      * are no more bytes to be read, this call returns -1.
783      * <p/>
784      * <P>If the byte array field value is null, <CODE>readBytes</CODE>
785      * returns -1.
786      * <p/>
787      * <P>If the byte array field value is empty, <CODE>readBytes</CODE>
788      * returns 0.
789      * <p/>
790      * <P>Once the first <CODE>readBytes</CODE> call on a <CODE>byte[]</CODE>
791      * field value has been made,
792      * the full value of the field must be read before it is valid to read
793      * the next field. An attempt to read the next field before that has
794      * been done will throw a <CODE>MessageFormatException</CODE>.
795      * <p/>
796      * <P>To read the byte field value into a new <CODE>byte[]</CODE> object,
797      * use the <CODE>readObject</CODE> method.
798      *
799      * @param value the buffer into which the data is read
800      * @return the total number of bytes read into the buffer, or -1 if
801      *         there is no more data because the end of the byte field has been
802      *         reached
803      * @throws JMSException                if the JMS provider fails to read the message
804      *                                     due to some internal error.
805      * @throws MessageEOFException         if unexpected end of message stream has
806      *                                     been reached.
807      * @throws MessageFormatException      if this type conversion is invalid.
808      * @throws MessageNotReadableException if the message is in write-only
809      *                                     mode.
810      * @see #readObject()
811      */
812 
813     public int readBytes(byte[] value) throws JMSException {
814         initializeReading();
815         try {
816             if (value == null) {
817                 throw new NullPointerException();
818             }
819             if (bytesToRead == 0) {
820                 bytesToRead = -1;
821                 return -1;
822             }
823             else if (bytesToRead > 0) {
824                 if (value.length >= bytesToRead) {
825                     bytesToRead = 0;
826                     return dataIn.read(value, 0, bytesToRead);
827                 }
828                 else {
829                     bytesToRead -= value.length;
830                     return dataIn.read(value);
831                 }
832             }
833             else {
834                 if (this.dataIn.available() == 0) {
835                     throw new MessageEOFException("reached end of data");
836                 }
837                 if (this.dataIn.available() < 1) {
838                     throw new MessageFormatException("Not enough data left to read value");
839                 }
840                 this.dataIn.mark(value.length + 1);
841                 int type = this.dataIn.read();
842                 if (this.dataIn.available() < 1) {
843                     return -1;
844                 }
845                 if (type != BYTES) {
846                     throw new MessageFormatException("Not a byte array");
847                 }
848                 int len = this.dataIn.readInt();
849 
850                 if (len >= value.length) {
851                     bytesToRead = len - value.length;
852                     return this.dataIn.read(value);
853                 }
854                 else {
855                     bytesToRead = 0;
856                     return this.dataIn.read(value, 0, len);
857                 }
858             }
859         }
860         catch (EOFException e) {
861             JMSException jmsEx = new MessageEOFException(e.getMessage());
862             jmsEx.setLinkedException(e);
863             throw jmsEx;
864         }
865         catch (IOException e) {
866             JMSException jmsEx = new MessageFormatException(e.getMessage());
867             jmsEx.setLinkedException(e);
868             throw jmsEx;
869         }
870     }
871 
872 
873     /**
874      * Reads an object from the stream message.
875      * <p/>
876      * <P>This method can be used to return, in objectified format,
877      * an object in the Java programming language ("Java object") that has
878      * been written to the stream with the equivalent
879      * <CODE>writeObject</CODE> method call, or its equivalent primitive
880      * <CODE>write<I>type</I></CODE> method.
881      * <p/>
882      * <P>Note that byte values are returned as <CODE>byte[]</CODE>, not
883      * <CODE>Byte[]</CODE>.
884      * <p/>
885      * <P>An attempt to call <CODE>readObject</CODE> to read a byte field
886      * value into a new <CODE>byte[]</CODE> object before the full value of the
887      * byte field has been read will throw a
888      * <CODE>MessageFormatException</CODE>.
889      *
890      * @return a Java object from the stream message, in objectified
891      *         format (for example, if the object was written as an <CODE>int</CODE>,
892      *         an <CODE>Integer</CODE> is returned)
893      * @throws JMSException                if the JMS provider fails to read the message
894      *                                     due to some internal error.
895      * @throws MessageEOFException         if unexpected end of message stream has
896      *                                     been reached.
897      * @throws MessageFormatException      if this type conversion is invalid.
898      * @throws MessageNotReadableException if the message is in write-only
899      *                                     mode.
900      * @see #readBytes(byte[] value)
901      */
902 
903     public Object readObject() throws JMSException {
904         initializeReading();
905         try {
906             if (this.dataIn.available() == 0) {
907                 throw new MessageEOFException("reached end of data");
908             }
909 
910             this.dataIn.mark(65);
911             int type = this.dataIn.read();
912             if (type == NULL) {
913                 return null;
914             }
915             if (type == STRING) {
916                 return this.dataIn.readUTF();
917             }
918             if (type == LONG) {
919                 return new Long(this.dataIn.readLong());
920             }
921             if (type == INT) {
922                 return new Integer(this.dataIn.readInt());
923             }
924             if (type == SHORT) {
925                 return new Short(this.dataIn.readShort());
926             }
927             if (type == BYTE) {
928                 return new Byte(this.dataIn.readByte());
929             }
930             if (type == FLOAT) {
931                 return new Float(this.dataIn.readFloat());
932             }
933             if (type == DOUBLE) {
934                 return new Double(this.dataIn.readDouble());
935             }
936             if (type == BOOLEAN) {
937                 return this.dataIn.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
938             }
939             if (type == CHAR) {
940                 return new Character(this.dataIn.readChar());
941             }
942             if (type == BYTES) {
943                 int len = this.dataIn.readInt();
944                 byte[] value = new byte[len];
945                 this.dataIn.read(value);
946                 return value;
947             }
948             else {
949                 this.dataIn.reset();
950                 throw new MessageFormatException("unknown type");
951             }
952         }
953         catch (NumberFormatException mfe) {
954             try {
955                 this.dataIn.reset();
956             }
957             catch (IOException ioe) {
958                 JMSException jmsEx = new JMSException("reset failed");
959                 jmsEx.setLinkedException(ioe);
960             }
961             throw mfe;
962 
963         }
964         catch (EOFException e) {
965             JMSException jmsEx = new MessageEOFException(e.getMessage());
966             jmsEx.setLinkedException(e);
967             throw jmsEx;
968         }
969         catch (IOException e) {
970             JMSException jmsEx = new MessageFormatException(e.getMessage());
971             jmsEx.setLinkedException(e);
972             throw jmsEx;
973         }
974     }
975 
976 
977     /**
978      * Writes a <code>boolean</code> to the stream message.
979      * The value <code>true</code> is written as the value
980      * <code>(byte)1</code>; the value <code>false</code> is written as
981      * the value <code>(byte)0</code>.
982      *
983      * @param value the <code>boolean</code> value to be written
984      * @throws JMSException                 if the JMS provider fails to write the message
985      *                                      due to some internal error.
986      * @throws MessageNotWriteableException if the message is in read-only
987      *                                      mode.
988      */
989 
990     public void writeBoolean(boolean value) throws JMSException {
991         initializeWriting();
992         try {
993             this.dataOut.write(BOOLEAN);
994             this.dataOut.writeBoolean(value);
995         }
996         catch (IOException ioe) {
997             JMSException jmsEx = new JMSException(ioe.getMessage());
998             jmsEx.setLinkedException(ioe);
999             throw jmsEx;
1000        }
1001    }
1002
1003
1004    /**
1005     * Writes a <code>byte</code> to the stream message.
1006     *
1007     * @param value the <code>byte</code> value to be written
1008     * @throws JMSException                 if the JMS provider fails to write the message
1009     *                                      due to some internal error.
1010     * @throws MessageNotWriteableException if the message is in read-only
1011     *                                      mode.
1012     */
1013
1014    public void writeByte(byte value) throws JMSException {
1015        initializeWriting();
1016        try {
1017            this.dataOut.write(BYTE);
1018            this.dataOut.writeByte(value);
1019        }
1020        catch (IOException ioe) {
1021            JMSException jmsEx = new JMSException(ioe.getMessage());
1022            jmsEx.setLinkedException(ioe);
1023            throw jmsEx;
1024        }
1025    }
1026
1027
1028    /**
1029     * Writes a <code>short</code> to the stream message.
1030     *
1031     * @param value the <code>short</code> value to be written
1032     * @throws JMSException                 if the JMS provider fails to write the message
1033     *                                      due to some internal error.
1034     * @throws MessageNotWriteableException if the message is in read-only
1035     *                                      mode.
1036     */
1037
1038    public void writeShort(short value) throws JMSException {
1039        initializeWriting();
1040        try {
1041            this.dataOut.write(SHORT);
1042            this.dataOut.writeShort(value);
1043        }
1044        catch (IOException ioe) {
1045            JMSException jmsEx = new JMSException(ioe.getMessage());
1046            jmsEx.setLinkedException(ioe);
1047            throw jmsEx;
1048        }
1049    }
1050
1051
1052    /**
1053     * Writes a <code>char</code> to the stream message.
1054     *
1055     * @param value the <code>char</code> value to be written
1056     * @throws JMSException                 if the JMS provider fails to write the message
1057     *                                      due to some internal error.
1058     * @throws MessageNotWriteableException if the message is in read-only
1059     *                                      mode.
1060     */
1061
1062    public void writeChar(char value) throws JMSException {
1063        initializeWriting();
1064        try {
1065            this.dataOut.write(CHAR);
1066            this.dataOut.writeChar(value);
1067        }
1068        catch (IOException ioe) {
1069            JMSException jmsEx = new JMSException(ioe.getMessage());
1070            jmsEx.setLinkedException(ioe);
1071            throw jmsEx;
1072        }
1073    }
1074
1075
1076    /**
1077     * Writes an <code>int</code> to the stream message.
1078     *
1079     * @param value the <code>int</code> value to be written
1080     * @throws JMSException                 if the JMS provider fails to write the message
1081     *                                      due to some internal error.
1082     * @throws MessageNotWriteableException if the message is in read-only
1083     *                                      mode.
1084     */
1085
1086    public void writeInt(int value) throws JMSException {
1087        initializeWriting();
1088        try {
1089            this.dataOut.write(INT);
1090            this.dataOut.writeInt(value);
1091        }
1092        catch (IOException ioe) {
1093            JMSException jmsEx = new JMSException(ioe.getMessage());
1094            jmsEx.setLinkedException(ioe);
1095            throw jmsEx;
1096        }
1097    }
1098
1099
1100    /**
1101     * Writes a <code>long</code> to the stream message.
1102     *
1103     * @param value the <code>long</code> value to be written
1104     * @throws JMSException                 if the JMS provider fails to write the message
1105     *                                      due to some internal error.
1106     * @throws MessageNotWriteableException if the message is in read-only
1107     *                                      mode.
1108     */
1109
1110    public void writeLong(long value) throws JMSException {
1111        initializeWriting();
1112        try {
1113            this.dataOut.write(LONG);
1114            this.dataOut.writeLong(value);
1115        }
1116        catch (IOException ioe) {
1117            JMSException jmsEx = new JMSException(ioe.getMessage());
1118            jmsEx.setLinkedException(ioe);
1119            throw jmsEx;
1120        }
1121    }
1122
1123
1124    /**
1125     * Writes a <code>float</code> to the stream message.
1126     *
1127     * @param value the <code>float</code> value to be written
1128     * @throws JMSException                 if the JMS provider fails to write the message
1129     *                                      due to some internal error.
1130     * @throws MessageNotWriteableException if the message is in read-only
1131     *                                      mode.
1132     */
1133
1134    public void writeFloat(float value) throws JMSException {
1135        initializeWriting();
1136        try {
1137            this.dataOut.write(FLOAT);
1138            this.dataOut.writeFloat(value);
1139        }
1140        catch (IOException ioe) {
1141            JMSException jmsEx = new JMSException(ioe.getMessage());
1142            jmsEx.setLinkedException(ioe);
1143            throw jmsEx;
1144        }
1145    }
1146
1147
1148    /**
1149     * Writes a <code>double</code> to the stream message.
1150     *
1151     * @param value the <code>double</code> value to be written
1152     * @throws JMSException                 if the JMS provider fails to write the message
1153     *                                      due to some internal error.
1154     * @throws MessageNotWriteableException if the message is in read-only
1155     *                                      mode.
1156     */
1157
1158    public void writeDouble(double value) throws JMSException {
1159        initializeWriting();
1160        try {
1161            this.dataOut.write(DOUBLE);
1162            this.dataOut.writeDouble(value);
1163        }
1164        catch (IOException ioe) {
1165            JMSException jmsEx = new JMSException(ioe.getMessage());
1166            jmsEx.setLinkedException(ioe);
1167            throw jmsEx;
1168        }
1169    }
1170
1171
1172    /**
1173     * Writes a <code>String</code> to the stream message.
1174     *
1175     * @param value the <code>String</code> value to be written
1176     * @throws JMSException                 if the JMS provider fails to write the message
1177     *                                      due to some internal error.
1178     * @throws MessageNotWriteableException if the message is in read-only
1179     *                                      mode.
1180     */
1181
1182    public void writeString(String value) throws JMSException {
1183        initializeWriting();
1184        try {
1185            if (value == null) {
1186                this.dataOut.write(NULL);
1187            }
1188            else {
1189                this.dataOut.write(STRING);
1190                this.dataOut.writeUTF(value);
1191            }
1192        }
1193        catch (IOException ioe) {
1194            JMSException jmsEx = new JMSException(ioe.getMessage());
1195            jmsEx.setLinkedException(ioe);
1196            throw jmsEx;
1197        }
1198    }
1199
1200
1201    /**
1202     * Writes a byte array field to the stream message.
1203     * <p/>
1204     * <P>The byte array <code>value</code> is written to the message
1205     * as a byte array field. Consecutively written byte array fields are
1206     * treated as two distinct fields when the fields are read.
1207     *
1208     * @param value the byte array value to be written
1209     * @throws JMSException                 if the JMS provider fails to write the message
1210     *                                      due to some internal error.
1211     * @throws MessageNotWriteableException if the message is in read-only
1212     *                                      mode.
1213     */
1214
1215    public void writeBytes(byte[] value) throws JMSException {
1216        writeBytes(value, 0, value.length);
1217    }
1218
1219
1220    /**
1221     * Writes a portion of a byte array as a byte array field to the stream
1222     * message.
1223     * <p/>
1224     * <P>The a portion of the byte array <code>value</code> is written to the
1225     * message as a byte array field. Consecutively written byte
1226     * array fields are treated as two distinct fields when the fields are
1227     * read.
1228     *
1229     * @param value  the byte array value to be written
1230     * @param offset the initial offset within the byte array
1231     * @param length the number of bytes to use
1232     * @throws JMSException                 if the JMS provider fails to write the message
1233     *                                      due to some internal error.
1234     * @throws MessageNotWriteableException if the message is in read-only
1235     *                                      mode.
1236     */
1237
1238    public void writeBytes(byte[] value, int offset, int length) throws JMSException {
1239        initializeWriting();
1240        try {
1241            this.dataOut.write(BYTES);
1242            this.dataOut.writeInt(length);
1243            this.dataOut.write(value, offset, length);
1244        }
1245        catch (IOException ioe) {
1246            JMSException jmsEx = new JMSException(ioe.getMessage());
1247            jmsEx.setLinkedException(ioe);
1248            throw jmsEx;
1249        }
1250    }
1251
1252
1253    /**
1254     * Writes an object to the stream message.
1255     * <p/>
1256     * <P>This method works only for the objectified primitive
1257     * object types (<code>Integer</code>, <code>Double</code>,
1258     * <code>Long</code>&nbsp;...), <code>String</code> objects, and byte
1259     * arrays.
1260     *
1261     * @param value the Java object to be written
1262     * @throws JMSException                 if the JMS provider fails to write the message
1263     *                                      due to some internal error.
1264     * @throws MessageFormatException       if the object is invalid.
1265     * @throws MessageNotWriteableException if the message is in read-only
1266     *                                      mode.
1267     */
1268
1269    public void writeObject(Object value) throws JMSException {
1270        initializeWriting();
1271        if (value == null) {
1272            try {
1273                this.dataOut.write(NULL);
1274            }
1275            catch (IOException ioe) {
1276                JMSException jmsEx = new JMSException(ioe.getMessage());
1277                jmsEx.setLinkedException(ioe);
1278                throw jmsEx;
1279            }
1280        }
1281        else if (value instanceof String) {
1282            writeString(value.toString());
1283        }
1284        else if (value instanceof Character) {
1285            writeChar(((Character) value).charValue());
1286        }
1287        else if (value instanceof Boolean) {
1288            writeBoolean(((Boolean) value).booleanValue());
1289        }
1290        else if (value instanceof Byte) {
1291            writeByte(((Byte) value).byteValue());
1292        }
1293        else if (value instanceof Short) {
1294            writeShort(((Short) value).shortValue());
1295        }
1296        else if (value instanceof Integer) {
1297            writeInt(((Integer) value).intValue());
1298        }
1299        else if (value instanceof Float) {
1300            writeFloat(((Float) value).floatValue());
1301        }
1302        else if (value instanceof Double) {
1303            writeDouble(((Double) value).doubleValue());
1304        }
1305        else if (value instanceof byte[]) {
1306            writeBytes((byte[]) value);
1307        }
1308    }
1309
1310
1311    /**
1312     * Puts the message body in read-only mode and repositions the stream of
1313     * bytes to the beginning.
1314     *
1315     * @throws JMSException if an internal error occurs
1316     */
1317
1318    public void reset() throws JMSException {
1319        super.readOnlyMessage = true;
1320        if (this.dataOut != null) {
1321            try {
1322                this.dataOut.flush();
1323                byte[] data = this.bytesOut.toByteArray();
1324                super.setBodyAsBytes(data,0,data.length);