KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > exolab > jms > message > StreamMessageImpl


1 /**
2  * Redistribution and use of this software and associated documentation
3  * ("Software"), with or without modification, are permitted provided
4  * that the following conditions are met:
5  *
6  * 1. Redistributions of source code must retain copyright
7  * statements and notices. Redistributions must also contain a
8  * copy of this document.
9  *
10  * 2. Redistributions in binary form must reproduce the
11  * above copyright notice, this list of conditions and the
12  * following disclaimer in the documentation and/or other
13  * materials provided with the distribution.
14  *
15  * 3. The name "Exolab" must not be used to endorse or promote
16  * products derived from this Software without prior written
17  * permission of Exoffice Technologies. For written permission,
18  * please contact info@exolab.org.
19  *
20  * 4. Products derived from this Software may not be called "Exolab"
21  * nor may "Exolab" appear in their names without prior written
22  * permission of Exoffice Technologies. Exolab is a registered
23  * trademark of Exoffice Technologies.
24  *
25  * 5. Due credit should be given to the Exolab Project
26  * (http://www.exolab.org/).
27  *
28  * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32  * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39  * OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * Copyright 2000-2004 (C) Exoffice Technologies Inc. All Rights Reserved.
42  *
43  * $Id: StreamMessageImpl.java,v 1.2 2005/05/24 13:27:10 tanderson Exp $
44  */

45 package org.exolab.jms.message;
46
47 import java.io.ByteArrayInputStream JavaDoc;
48 import java.io.ByteArrayOutputStream JavaDoc;
49 import java.io.DataInputStream JavaDoc;
50 import java.io.DataOutputStream JavaDoc;
51 import java.io.EOFException JavaDoc;
52 import java.io.IOException JavaDoc;
53 import java.io.ObjectInput JavaDoc;
54 import java.io.ObjectOutput JavaDoc;
55
56 import javax.jms.JMSException JavaDoc;
57 import javax.jms.MessageEOFException JavaDoc;
58 import javax.jms.MessageFormatException JavaDoc;
59 import javax.jms.MessageNotReadableException JavaDoc;
60 import javax.jms.MessageNotWriteableException JavaDoc;
61 import javax.jms.StreamMessage JavaDoc;
62
63
64 /**
65  * This class implements the {@link javax.jms.StreamMessage} interface.
66  * <p>
67  * A StreamMessage is used to send a stream of Java primitives.
68  * It is filled and read sequentially. It inherits from <code>Message</code>
69  * and adds a stream message body. It's methods are based largely on those
70  * found in <code>java.io.DataInputStream</code> and
71  * <code>java.io.DataOutputStream</code>.
72  * <p>
73  * The primitive types can be read or written explicitly using methods
74  * for each type. They may also be read or written generically as objects.
75  * For instance, a call to <code>StreamMessage.writeInt(6)</code> is
76  * equivalent to <code>StreamMessage.writeObject(new Integer(6))</code>.
77  * Both forms are provided because the explicit form is convenient for
78  * static programming and the object form is needed when types are not known
79  * at compile time.
80  * <p>
81  * When the message is first created, and when {@link #clearBody}
82  * is called, the body of the message is in write-only mode. After the
83  * first call to {@link #reset} has been made, the message body is in
84  * read-only mode. When a message has been sent, by definition, the
85  * provider calls <code>reset</code> in order to read it's content, and
86  * when a message has been received, the provider has called
87  * <code>reset</code> so that the message body is in read-only mode for the
88  * client.
89  * <p>
90  * If {@link #clearBody} is called on a message in read-only mode,
91  * the message body is cleared and the message body is in write-only mode.
92  * <p>
93  * If a client attempts to read a message in write-only mode, a
94  * MessageNotReadableException is thrown.
95  * <p>
96  * If a client attempts to write a message in read-only mode, a
97  * MessageNotWriteableException is thrown.
98  * <p>
99  * Stream messages support the following conversion table. The marked cases
100  * must be supported. The unmarked cases must throw a JMSException. The
101  * String to primitive conversions may throw a runtime exception if the
102  * primitives <code>valueOf()</code> method does not accept it as a valid
103  * String representation of the primitive.
104  * <p>
105  * A value written as the row type can be read as the column type.
106  *
107  * <pre>
108  * | | boolean byte short char int long float double String byte[]
109  * |----------------------------------------------------------------------
110  * |boolean | X X
111  * |byte | X X X X X
112  * |short | X X X X
113  * |char | X X
114  * |int | X X X
115  * |long | X X
116  * |float | X X X
117  * |double | X X
118  * |String | X X X X X X X X
119  * |byte[] | X
120  * |----------------------------------------------------------------------
121  * </pre>
122  * <p>
123  * Attempting to read a null value as a Java primitive type must be treated
124  * as calling the primitive's corresponding <code>valueOf(String)</code>
125  * conversion method with a null value. Since char does not support a String
126  * conversion, attempting to read a null value as a char must throw
127  * NullPointerException.
128  *
129  * @version $Revision: 1.2 $ $Date: 2005/05/24 13:27:10 $
130  * @author <a HREF="mailto:mourikis@intalio.com">Jim Mourikis</a>
131  * @author <a HREF="mailto:tma@netspace.net.au">Tim Anderson</a>
132  * @see javax.jms.StreamMessage
133  */

134 public final class StreamMessageImpl extends MessageImpl
135     implements StreamMessage JavaDoc {
136
137     /**
138      * Object version no. for serialization
139      */

140     static final long serialVersionUID = 2;
141
142     /**
143      * Type codes
144      */

145     private static final byte NULL = 0;
146     private static final byte BOOLEAN = 1;
147     private static final byte BYTE = 2;
148     private static final byte BYTE_ARRAY = 3;
149     private static final byte SHORT = 4;
150     private static final byte CHAR = 5;
151     private static final byte INT = 6;
152     private static final byte LONG = 7;
153     private static final byte FLOAT = 8;
154     private static final byte DOUBLE = 9;
155     private static final byte STRING = 10;
156
157     /**
158      * String values representing the above type codes, for error reporting
159      * purposes
160      */

161     private static final String JavaDoc[] TYPE_NAMES = {
162         "null", "boolean", "byte", "byte[]", "short", "char", "int", "long",
163         "float", "double", "String"};
164
165     /**
166      * Empty byte array for initialisation purposes
167      */

168     private static final byte[] EMPTY = new byte[]{};
169
170     /**
171      * The byte stream to store data
172      */

173     private byte[] _bytes = EMPTY;
174
175     /**
176      * The stream used for writes
177      */

178     private DataOutputStream JavaDoc _out = null;
179
180     /**
181      * The byte stream backing the output stream
182      */

183     private ByteArrayOutputStream JavaDoc _byteOut = null;
184
185     /**
186      * The stream used for reads
187      */

188     private DataInputStream JavaDoc _in = null;
189
190     /**
191      * The byte stream backing the input stream
192      */

193     private ByteArrayInputStream JavaDoc _byteIn = null;
194
195     /**
196      * Non-zero if incrementally reading a byte array using
197      * {@link #readBytes(byte[])}
198      */

199     private int _readBytes = 0;
200
201     /**
202      * The length of the byte array being read using {@link #readBytes(byte[])}
203      */

204     private int _byteArrayLength = 0;
205
206     /**
207      * The offset of the byte stream to start reading from. This defaults
208      * to 0, and only applies to messages that are cloned from a
209      * read-only instance where part of the stream had already been read.
210      */

211     private int _offset = 0;
212
213
214     /**
215      * Construct a new StreamMessage. When first created, the message is in
216      * write-only mode.
217      *
218      * @throws JMSException if the message type can't be set, or an I/O error
219      * occurs
220      */

221     public StreamMessageImpl() throws JMSException JavaDoc {
222         setJMSType("StreamMessage");
223     }
224
225     /**
226      * Clone an instance of this object
227      *
228      * @return a copy of this object
229      * @throws CloneNotSupportedException if object or attributes aren't
230      * cloneable
231      */

232     public final Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
233         StreamMessageImpl result = (StreamMessageImpl) super.clone();
234         if (_bodyReadOnly) {
235             result._bytes = new byte[_bytes.length];
236             System.arraycopy(_bytes, 0, result._bytes, 0, _bytes.length);
237             if (_byteIn != null) {
238                 // if a client subsequently reads from the cloned object,
239
// start reading from offset of the original stream
240
_offset = _bytes.length - _byteIn.available();
241             }
242             result._byteIn = null;
243             result._in = null;
244         } else {
245             if (_out != null) {
246                 try {
247                     _out.flush();
248                 } catch (IOException JavaDoc exception) {
249                     throw new CloneNotSupportedException JavaDoc(
250                         exception.getMessage());
251                 }
252                 result._bytes = _byteOut.toByteArray();
253                 result._byteOut = null;
254                 result._out = null;
255             } else {
256                 result._bytes = new byte[_bytes.length];
257                 System.arraycopy(_bytes, 0, result._bytes, 0, _bytes.length);
258             }
259         }
260
261         return result;
262     }
263
264     /**
265      * Serialize out this message's data
266      *
267      * @param out the stream to serialize out to
268      * @throws IOException if any I/O exceptions occurr
269      */

270     public final void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
271         // If it was in write mode, extract the byte array
272
if (!_bodyReadOnly && _out != null) {
273             _out.flush();
274             _bytes = _byteOut.toByteArray();
275         }
276
277         super.writeExternal(out);
278         out.writeLong(serialVersionUID);
279         out.writeInt(_bytes.length);
280         out.write(_bytes);
281         out.flush();
282     }
283
284     /**
285      * Serialize in this message's data
286      *
287      * @param in the stream to serialize in from
288      * @throws ClassNotFoundException if the class for an object being
289      * restored cannot be found.
290      * @throws IOException if any I/O exceptions occur
291      */

292     public final void readExternal(ObjectInput JavaDoc in)
293         throws ClassNotFoundException JavaDoc, IOException JavaDoc {
294         super.readExternal(in);
295         long version = in.readLong();
296         if (version == serialVersionUID) {
297             int length = in.readInt();
298             _bytes = new byte[length];
299             in.readFully(_bytes);
300         } else {
301             throw new IOException JavaDoc("Incorrect version enountered: " + version
302                                   + ". This version = " + serialVersionUID);
303         }
304     }
305
306     /**
307      * Read a <code>boolean</code> from the bytes message stream
308      *
309      * @return the <code>boolean</code> value read
310      * @throws JMSException if JMS fails to read message due to some internal
311      * JMS error
312      * @throws MessageEOFException if end of message stream
313      * @throws MessageFormatException if this type conversion is invalid
314      * @throws MessageNotReadableException if message is in write-only mode
315      */

316     public final boolean readBoolean() throws JMSException JavaDoc {
317         boolean result = false;
318         prepare();
319         try {
320             result = FormatConverter.getBoolean(readNext());
321         } catch (MessageFormatException JavaDoc exception) {
322             revert(exception);
323         }
324         return result;
325     }
326
327     /**
328      * Read a byte value from the stream message
329      *
330      * @return the next byte from the stream message as an 8-bit
331      * <code>byte</code>
332      * @throws JMSException if JMS fails to read message due to some internal
333      * JMS error
334      * @throws MessageEOFException if end of message stream
335      * @throws MessageFormatException if this type conversion is invalid
336      * @throws MessageNotReadableException if message is in write-only mode
337      * @throws NumberFormatException if numeric conversion is invalid
338      */

339     public final byte readByte() throws JMSException JavaDoc {
340         byte result = 0;
341         prepare();
342         try {
343             result = FormatConverter.getByte(readNext());
344         } catch (MessageFormatException JavaDoc exception) {
345             revert(exception);
346         } catch (NumberFormatException JavaDoc exception) {
347             revert(exception);
348         }
349         return result;
350     }
351
352     /**
353      * Read a 16-bit number from the stream message.
354      *
355      * @return a 16-bit number from the stream message
356      * @throws JMSException if JMS fails to read message due to some internal
357      * JMS error
358      * @throws MessageEOFException if end of message stream
359      * @throws MessageFormatException if this type conversion is invalid
360      * @throws MessageNotReadableException if message is in write-only mode
361      * @throws NumberFormatException if numeric conversion is invalid
362      */

363     public final short readShort() throws JMSException JavaDoc {
364         short result = 0;
365         prepare();
366         try {
367             result = FormatConverter.getShort(readNext());
368         } catch (MessageFormatException JavaDoc exception) {
369             revert(exception);
370         } catch (NumberFormatException JavaDoc exception) {
371             revert(exception);
372         }
373         return result;
374     }
375
376     /*
377      * Read a Unicode character value from the stream message
378      *
379      * @return a Unicode character from the stream message
380      * @throws JMSException if JMS fails to read message due to some internal
381      * JMS error
382      * @throws MessageEOFException if end of message stream
383      * @throws MessageFormatException if this type conversion is invalid
384      * @throws MessageNotReadableException if message is in write-only mode
385      */

386     public final char readChar() throws JMSException JavaDoc {
387         char result = 0;
388         prepare();
389         try {
390             result = FormatConverter.getChar(readNext());
391         } catch (MessageFormatException JavaDoc exception) {
392             revert(exception);
393         } catch (NullPointerException JavaDoc exception) {
394             revert(exception);
395         }
396         return result;
397     }
398
399     /*
400      * Read a 32-bit integer from the stream message
401      *
402      * @return a 32-bit integer value from the stream message, interpreted
403      * as an <code>int</code>
404      * @throws JMSException if JMS fails to read message due to some internal
405      * JMS error
406      * @throws MessageEOFException if end of message stream
407      * @throws MessageFormatException if this type conversion is invalid
408      * @throws MessageNotReadableException if message is in write-only mode
409      * @throws NumberFormatException if numeric conversion is invalid
410      */

411     public final int readInt() throws JMSException JavaDoc {
412         int result = 0;
413         prepare();
414         try {
415             result = FormatConverter.getInt(readNext());
416         } catch (MessageFormatException JavaDoc exception) {
417             revert(exception);
418         } catch (NumberFormatException JavaDoc exception) {
419             revert(exception);
420         }
421         return result;
422     }
423
424     /*
425      * Read a 64-bit integer from the stream message
426      *
427      * @return a 64-bit integer value from the stream message, interpreted as
428      * a <code>long</code>
429      * @throws JMSException if JMS fails to read message due to some internal
430      * JMS error
431      * @throws MessageEOFException if end of message stream
432      * @throws MessageFormatException if this type conversion is invalid
433      * @throws MessageNotReadableException if message is in write-only mode
434      * @throws NumberFormatException if numeric conversion is invalid
435      */

436     public final long readLong() throws JMSException JavaDoc {
437         long result = 0;
438         prepare();
439         try {
440             result = FormatConverter.getLong(readNext());
441         } catch (MessageFormatException JavaDoc exception) {
442             revert(exception);
443         } catch (NumberFormatException JavaDoc exception) {
444             revert(exception);
445         }
446         return result;
447     }
448
449     /**
450      * Read a <code>float</code> from the stream message
451      *
452      * @return a <code>float</code> value from the stream message
453      * @throws JMSException if JMS fails to read message due to some internal
454      * JMS error
455      * @throws MessageEOFException if end of message stream
456      * @throws MessageFormatException if this type conversion is invalid
457      * @throws MessageNotReadableException if message is in write-only mode
458      * @throws NullPointerException if the value is null
459      * @throws NumberFormatException if numeric conversion is invalid
460      */

461     public final float readFloat() throws JMSException JavaDoc {
462         float result = 0;
463         prepare();
464         try {
465             result = FormatConverter.getFloat(readNext());
466         } catch (MessageFormatException JavaDoc exception) {
467             revert(exception);
468         } catch (NullPointerException JavaDoc exception) {
469             revert(exception);
470         } catch (NumberFormatException JavaDoc exception) {
471             revert(exception);
472         }
473         return result;
474     }
475
476     /**
477      * Read a <code>double</code> from the stream message
478      *
479      * @return a <code>double</code> value from the stream message
480      * @throws JMSException if JMS fails to read message due to some internal
481      * JMS error
482      * @throws MessageEOFException if end of message stream
483      * @throws MessageFormatException if this type conversion is invalid
484      * @throws MessageNotReadableException if message is in write-only mode
485      * @throws NullPointerException if the value is null
486      * @throws NumberFormatException if numeric conversion is invalid
487      */

488     public final double readDouble() throws JMSException JavaDoc {
489         double result = 0;
490         prepare();
491         try {
492             result = FormatConverter.getDouble(readNext());
493         } catch (MessageFormatException JavaDoc exception) {
494             revert(exception);
495         } catch (NullPointerException JavaDoc exception) {
496             revert(exception);
497         } catch (NumberFormatException JavaDoc exception) {
498             revert(exception);
499         }
500         return result;
501     }
502
503     /**
504      * Read in a string from the stream message
505      *
506      * @return a Unicode string from the stream message
507      * @throws JMSException if JMS fails to read message due to some internal
508      * JMS error
509      * @throws MessageEOFException if end of message stream
510      * @throws MessageFormatException if this type conversion is invalid
511      * @throws MessageNotReadableException if message is in write-only mode
512      */

513     public final String JavaDoc readString() throws JMSException JavaDoc {
514         String JavaDoc result = null;
515         prepare();
516         try {
517             result = FormatConverter.getString(readNext());
518         } catch (MessageFormatException JavaDoc exception) {
519             revert(exception);
520         }
521         return result;
522     }
523
524     /**
525      * Read a byte array field from the stream message into the
526      * specified byte[] object (the read buffer).
527      * <p>
528      * To read the field value, readBytes should be successively called
529      * until it returns a value less than the length of the read buffer.
530      * The value of the bytes in the buffer following the last byte
531      * read are undefined.
532      * <p>
533      * If readBytes returns a value equal to the length of the buffer, a
534      * subsequent readBytes call must be made. If there are no more bytes
535      * to be read this call will return -1.
536      * <p>
537      * If the bytes array field value is null, readBytes returns -1.
538      * <p>
539      * If the bytes array field value is empty, readBytes returns 0.
540      * <p>
541      * Once the first readBytes call on a byte[] field value has been done,
542      * the full value of the field must be read before it is valid to read
543      * the next field. An attempt to read the next field before that has
544      * been done will throw a MessageFormatException.
545      * <p>
546      * To read the byte field value into a new byte[] object, use the
547      * {@link #readObject} method.
548      *
549      * @param value the buffer into which the data is read.
550      * @return the total number of bytes read into the buffer, or -1 if
551      * there is no more data because the end of the byte field has been
552      * reached.
553      * @throws JMSException if JMS fails to read message due to some internal
554      * JMS error
555      * @throws MessageEOFException if an end of message stream
556      * @throws MessageFormatException if this type conversion is invalid
557      * @throws MessageNotReadableException if message is in write-only mode
558      */

559     public final int readBytes(byte[] value) throws JMSException JavaDoc {
560         checkRead();
561         getInputStream();
562         int read = 0; // the number of bytes read
563
if (_readBytes == 0) {
564             // read the next byte array field
565
try {
566                 _in.mark(_bytes.length - _in.available());
567                 byte type = (byte) (_in.readByte() & 0x0F);
568                 if (type == NULL) {
569                     return -1;
570                 } else if (type != BYTE_ARRAY) {
571                     _in.reset();
572                     if (type < TYPE_NAMES.length) {
573                         throw new MessageFormatException JavaDoc(
574                             "Expected type=" + TYPE_NAMES[BYTE_ARRAY]
575                             + ", but got type=" + TYPE_NAMES[type]);
576                     } else {
577                         throw new MessageFormatException JavaDoc(
578                             "StreamMessage corrupted");
579                     }
580                 }
581             } catch (IOException JavaDoc exception) {
582                 raise(exception);
583             }
584             try {
585                 _byteArrayLength = _in.readInt();
586             } catch (IOException JavaDoc exception) {
587                 raise(exception);
588             }
589         }
590
591         if (_byteArrayLength == 0) {
592             // No bytes to read. Return -1 if this is an incremental read
593
// or 0 if the byte array was empty
594
if (_readBytes != 0) {
595                 // completing an incremental read
596
read = -1;
597             }
598             _readBytes = 0; // indicates finished reading the byte array
599
} else if (value.length <= _byteArrayLength) {
600             // bytes to read >= size of target
601
read = value.length;
602             try {
603                 _in.readFully(value);
604             } catch (IOException JavaDoc exception) {
605                 raise(exception);
606             }
607             _byteArrayLength -= value.length;
608             ++_readBytes;
609         } else {
610             // bytes to read < size of target
611
read = _byteArrayLength;
612             try {
613                 _in.readFully(value, 0, _byteArrayLength);
614             } catch (IOException JavaDoc exception) {
615                 raise(exception);
616             }
617             _readBytes = 0;
618         }
619         return read;
620     }
621
622     /**
623      * Read a Java object from the stream message
624      * <p>
625      * Note that this method can be used to return in objectified format,
626      * an object that had been written to the stream with the equivalent
627      * <code>writeObject</code> method call, or it's equivalent primitive
628      * write<type> method.
629      * <p>
630      * Note that byte values are returned as byte[], not Byte[].
631      *
632      * @return a Java object from the stream message, in objectified
633      * format (eg. if it set as an int, then a Integer is returned).
634      * @throws JMSException if JMS fails to read message due to some internal
635      * JMS error
636      * @throws MessageEOFException if end of message stream
637      * @throws MessageNotReadableException if message is in write-only mode
638      */

639     public final Object JavaDoc readObject() throws JMSException JavaDoc {
640         Object JavaDoc result = null;
641         prepare();
642         try {
643             result = readNext();
644         } catch (MessageFormatException JavaDoc exception) {
645             revert(exception);
646         }
647         return result;
648     }
649
650     /**
651      * Write a <code>boolean</code> to the stream message.
652      * The value <code>true</code> is written out as the value
653      * <code>(byte)1</code>; the value <code>false</code> is written out as
654      * the value <code>(byte)0</code>.
655      *
656      * @param value the <code>boolean</code> value to be written.
657      * @throws JMSException if JMS fails to write message due to
658      * some internal JMS error
659      * @throws MessageNotWriteableException if message in read-only mode
660      */

661     public final void writeBoolean(boolean value) throws JMSException JavaDoc {
662         checkWrite();
663         try {
664             getOutputStream();
665             // encode the boolean value in the type byte
666
_out.writeByte(BOOLEAN | ((value) ? 1 << 4 : 0));
667         } catch (IOException JavaDoc exception) {
668             raise(exception);
669         }
670     }
671
672     /**
673      * Write out a <code>byte</code> to the stream message
674      *
675      * @param value the <code>byte</code> value to be written
676      * @throws JMSException if JMS fails to write message due to
677      * some internal JMS error
678      * @throws MessageNotWriteableException if message in read-only mode
679      */

680     public final void writeByte(byte value) throws JMSException JavaDoc {
681         checkWrite();
682         try {
683             getOutputStream();
684             _out.writeByte(BYTE);
685             _out.writeByte(value);
686         } catch (IOException JavaDoc exception) {
687             raise(exception);
688         }
689     }
690
691     /**
692      * Write a <code>short</code> to the stream message
693      *
694      * @param value the <code>short</code> to be written
695      * @throws JMSException if JMS fails to write message due to
696      * some internal JMS error
697      * @throws MessageNotWriteableException if message in read-only mode
698      */

699     public final void writeShort(short value) throws JMSException JavaDoc {
700         checkWrite();
701         try {
702             getOutputStream();
703             _out.writeByte(SHORT);
704             _out.writeShort(value);
705         } catch (IOException JavaDoc exception) {
706             raise(exception);
707         }
708     }
709
710     /**
711      * Write a <code>char</code> to the stream message
712      *
713      * @param value the <code>char</code> value to be written
714      * @throws JMSException if JMS fails to write message due to
715      * some internal JMS error
716      * @throws MessageNotWriteableException if message in read-only mode
717      */

718     public final void writeChar(char value) throws JMSException JavaDoc {
719         checkWrite();
720         try {
721             getOutputStream();
722             _out.writeByte(CHAR);
723             _out.writeChar(value);
724         } catch (IOException JavaDoc exception) {
725             raise(exception);
726         }
727     }
728
729     /**
730      * Write an <code>int</code> to the stream message
731      *
732      * @param value the <code>int</code> to be written
733      * @throws JMSException if JMS fails to write message due to
734      * some internal JMS error
735      * @throws MessageNotWriteableException if message in read-only mode
736      */

737     public final void writeInt(int value) throws JMSException JavaDoc {
738         checkWrite();
739         try {
740             getOutputStream();
741             _out.writeByte(INT);
742             _out.writeInt(value);
743         } catch (IOException JavaDoc exception) {
744             raise(exception);
745         }
746     }
747
748     /**
749      * Write a <code>long</code> to the stream message
750      *
751      * @param value the <code>long</code> to be written
752      * @throws JMSException if JMS fails to write message due to
753      * some internal JMS error
754      * @throws MessageNotWriteableException if message in read-only mode
755      */

756     public final void writeLong(long value) throws JMSException JavaDoc {
757         checkWrite();
758         try {
759             getOutputStream();
760             _out.writeByte(LONG);
761             _out.writeLong(value);
762         } catch (IOException JavaDoc exception) {
763             raise(exception);
764         }
765     }
766
767     /**
768      * Write a <code>float</code> to the stream message
769      *
770      * @param value the <code>float</code> value to be written
771      * @throws JMSException if JMS fails to write message due to
772      * some internal JMS error
773      * @throws MessageNotWriteableException if message in read-only mode
774      */

775     public final void writeFloat(float value) throws JMSException JavaDoc {
776         checkWrite();
777         try {
778             getOutputStream();
779             _out.writeByte(FLOAT);
780             _out.writeFloat(value);
781         } catch (IOException JavaDoc exception) {
782             raise(exception);
783         }
784     }
785
786     /**
787      * Write a <code>double</code> to the stream message
788      *
789      * @param value the <code>double</code> value to be written
790      * @throws JMSException if JMS fails to write message due to
791      * some internal JMS error
792      * @throws MessageNotWriteableException if message in read-only mode
793      */

794     public final void writeDouble(double value) throws JMSException JavaDoc {
795         checkWrite();
796         try {
797             getOutputStream();
798             _out.writeByte(DOUBLE);
799             _out.writeDouble(value);
800         } catch (IOException JavaDoc exception) {
801             raise(exception);
802         }
803     }
804
805     /**
806      * Write a string to the stream message
807      *
808      * @param value the <code>String</code> value to be written
809      * @throws JMSException if JMS fails to write message due to
810      * some internal JMS error
811      * @throws MessageNotWriteableException if message in read-only mode
812      * @throws NullPointerException if value is null
813      */

814     public final void writeString(String JavaDoc value) throws JMSException JavaDoc {
815         checkWrite();
816         if (value == null) {
817             // could throw IllegalArgumentException, but this is in keeping
818
// with that thrown by DataOutputStream
819
throw new NullPointerException JavaDoc("Argument value is null");
820         }
821         try {
822             getOutputStream();
823             _out.writeByte(STRING);
824             _out.writeUTF(value);
825         } catch (IOException JavaDoc exception) {
826             raise(exception);
827         }
828     }
829
830     /**
831      * Write a byte array field to the stream message
832      * <p>
833      * The byte array <code>value</code> is written as a byte array field
834      * into the StreamMessage. Consecutively written byte array fields are
835      * treated as two distinct fields when reading byte array fields.
836      *
837      * @param value the byte array to be written
838      * @throws JMSException if JMS fails to write message due to
839      * some internal JMS error
840      * @throws MessageNotWriteableException if message in read-only mode
841      * @throws NullPointerException if value is null
842      */

843     public final void writeBytes(byte[] value) throws JMSException JavaDoc {
844         checkWrite();
845         if (value == null) {
846             // could throw IllegalArgumentException, but this is in keeping
847
// with that thrown by DataOutputStream
848
throw new NullPointerException JavaDoc("Argument value is null");
849         }
850         try {
851             getOutputStream();
852             _out.writeByte(BYTE_ARRAY);
853             _out.writeInt(value.length);
854             _out.write(value);
855         } catch (IOException JavaDoc exception) {
856             raise(exception);
857         }
858     }
859
860     /**
861      * Write a portion of a byte array as a byte array field to the stream
862      * message
863      * <p>
864      * The a portion of the byte array <code>value</code> is written as a
865      * byte array field into the StreamMessage. Consecutively written byte
866      * array fields are treated as two distinct fields when reading byte
867      * array fields.
868      *
869      * @param value the byte array value to be written
870      * @param offset the initial offset within the byte array
871      * @param length the number of bytes to write
872      * @throws JMSException if JMS fails to write message due to
873      * some internal JMS error
874      * @throws MessageNotWriteableException if message in read-only mode
875      * @throws NullPointerException if value is null
876      */

877     public void writeBytes(byte[] value, int offset, int length)
878         throws JMSException JavaDoc {
879         checkWrite();
880         if (value == null) {
881             // could throw IllegalArgumentException, but this is in keeping
882
// with that thrown by DataOutputStream
883
throw new NullPointerException JavaDoc("Argument value is null");
884         }
885         try {
886             getOutputStream();
887             _out.writeByte(BYTE_ARRAY);
888             _out.writeInt(length);
889             _out.write(value, offset, length);
890         } catch (IOException JavaDoc exception) {
891             raise(exception);
892         }
893     }
894
895     /**
896      * Write a Java object to the stream message
897      * <p>
898      * Note that this method only works for the objectified primitive
899      * object types (Integer, Double, Long ...), String's and byte arrays.
900      *
901      * @param value the Java object to be written
902      * @throws JMSException if JMS fails to write message due to
903      * some internal JMS error
904      * @throws MessageFormatException if the object is invalid
905      * @throws MessageNotWriteableException if message in read-only mode
906      */

907     public void writeObject(Object JavaDoc value) throws JMSException JavaDoc {
908         if (value == null) {
909             try {
910                 checkWrite();
911                 getOutputStream();
912                 _out.writeByte(NULL);
913             } catch (IOException JavaDoc exception) {
914                 raise(exception);
915             }
916         } else if (value instanceof Boolean JavaDoc) {
917             writeBoolean(((Boolean JavaDoc) value).booleanValue());
918         } else if (value instanceof Byte JavaDoc) {
919             writeByte(((Byte JavaDoc) value).byteValue());
920         } else if (value instanceof byte[]) {
921             writeBytes((byte[]) value);
922         } else if (value instanceof Short JavaDoc) {
923             writeShort(((Short JavaDoc) value).shortValue());
924         } else if (value instanceof Character JavaDoc) {
925             writeChar(((Character JavaDoc) value).charValue());
926         } else if (value instanceof Integer JavaDoc) {
927             writeInt(((Integer JavaDoc) value).intValue());
928         } else if (value instanceof Long JavaDoc) {
929             writeLong(((Long JavaDoc) value).longValue());
930         } else if (value instanceof Float JavaDoc) {
931             writeFloat(((Float JavaDoc) value).floatValue());
932         } else if (value instanceof Double JavaDoc) {
933             writeDouble(((Double JavaDoc) value).doubleValue());
934         } else if (value instanceof String JavaDoc) {
935             writeString((String JavaDoc) value);
936         } else {
937             throw new MessageFormatException JavaDoc(
938                 "Objects of type " + value.getClass().getName()
939                 + " are not supported by StreamMessage");
940         }
941     }
942
943     /**
944      * Put the message body in read-only mode, and reposition the stream
945      * to the beginning
946      *
947      * @throws JMSException if JMS fails to reset the message due to
948      * some internal JMS error
949      */

950     public void reset() throws JMSException JavaDoc {
951         try {
952             if (!_bodyReadOnly) {
953                 _bodyReadOnly = true;
954                 if (_out != null) {
955                     _out.flush();
956                     _bytes = _byteOut.toByteArray();
957                     _byteOut = null;
958                     _out.close();
959                     _out = null;
960                 }
961             } else {
962                 if (_in != null) {
963                     _byteIn = null;
964                     _in.close();
965                     _in = null;
966                 }
967             }
968             _readBytes = 0;
969         } catch (IOException JavaDoc exception) {
970             raise(exception);
971         }
972     }
973
974     /**
975      * Overide the super class method to reset the streams, and put the
976      * message body in write only mode
977      *
978      * @throws JMSException if JMS fails to reset the message due to
979      * some internal JMS error.
980      */

981     public void clearBody() throws JMSException JavaDoc {
982         try {
983             if (_bodyReadOnly) {
984                 // in read-only mode
985
_bodyReadOnly = false;
986                 if (_in != null) {
987                     _byteIn = null;
988                     _in.close();
989                     _in = null;
990                     _offset = 0;
991                 }
992             } else if (_out != null) {
993                 // already in write-only mode
994
_byteOut = null;
995                 _out.close();
996                 _out = null;
997             }
998             _bytes = EMPTY;
999             _readBytes = 0;
1000        } catch (IOException JavaDoc exception) {
1001            raise(exception);
1002        }
1003    }
1004
1005    /**
1006     * Set the read-only mode of the message. If read-only, resets the message
1007     * for reading
1008     *
1009     * @param readOnly if true, make the message body and properties
1010     * @throws JMSException if the read-only mode cannot be changed
1011     */

1012    public final void setReadOnly(boolean readOnly) throws JMSException JavaDoc {
1013        if (readOnly) {
1014            reset();
1015        }
1016        super.setReadOnly(readOnly);
1017    }
1018
1019    /**
1020     * Prepare to do a read
1021     *
1022     * @throws JMSException if the current position in the stream can't be
1023     * marked
1024     * @throws MessageNotReadableException if the message is in write-only mode
1025     */

1026    private final void prepare() throws JMSException JavaDoc {
1027        checkRead();
1028        getInputStream();
1029        try {
1030            _in.mark(_bytes.length - _in.available());
1031        } catch (IOException JavaDoc exception) {
1032            raise(exception);
1033        }
1034    }
1035
1036    /**
1037     * Reverts the stream to its prior position if a MessageFormatException is
1038     * thrown, and propagates the exception.
1039     *
1040     * @param exception the exception that caused the reset
1041     * @throws MessageFormatException
1042     */

1043    private void revert(MessageFormatException JavaDoc exception)
1044        throws MessageFormatException JavaDoc {
1045        try {
1046            _in.reset();
1047        } catch (IOException JavaDoc ignore) {
1048            // can't reset the stream, but need to propagate the original
1049
// exception
1050
}
1051        throw exception;
1052    }
1053
1054    /**
1055     * Reverts the stream to its prior position if a NumberFormatException or
1056     * NullPointerException is thrown, and propagates the exception.
1057     *
1058     * @param exception the exception that caused the reset
1059     * @throws NullPointerException
1060     * @throws NumberFormatException
1061     */

1062    private void revert(RuntimeException JavaDoc exception) {
1063        try {
1064            _in.reset();
1065        } catch (IOException JavaDoc ignore) {
1066            // can't reset the stream, but need to propagate the original
1067
// exception
1068
}
1069        throw exception;
1070    }
1071
1072    /**
1073     * Read the next object from the stream message
1074     *
1075     * @return a Java object from the stream message, in objectified
1076     * format (eg. if it set as an int, then a Integer is returned).
1077     * @throws JMSException if JMS fails to read message due to some internal
1078     * JMS error
1079     * @throws MessageEOFException if end of message stream
1080     * @throws MessageFormatException if a byte array has not been fully read
1081     * by {@link #readBytes(byte[])}
1082     * @throws MessageNotReadableException if the message is in write-only mode
1083     */

1084    private Object JavaDoc readNext() throws JMSException JavaDoc {
1085        if (_readBytes != 0) {
1086            throw new MessageFormatException JavaDoc(
1087                "Cannot read the next field until the byte array is read");
1088        }
1089
1090        byte type = 0;
1091        try {
1092            type = _in.readByte();
1093        } catch (IOException JavaDoc exception) {
1094            raise(exception);
1095        }
1096        if ((type & 0x0F) > TYPE_NAMES.length) {
1097            throw new JMSException JavaDoc("StreamMessage corrupted");
1098        }
1099        Object JavaDoc result = null;
1100
1101        try {
1102            switch (type & 0x0F) {
1103                case BOOLEAN:
1104                    boolean value = ((type & 0xF0) != 0) ? true : false;
1105                    result = new Boolean JavaDoc(value);
1106                    break;
1107                case BYTE:
1108                    result = new Byte JavaDoc(_in.readByte());
1109                    break;
1110                case BYTE_ARRAY:
1111                    int length = _in.readInt();
1112                    byte[] bytes = new byte[length];
1113                    _in.readFully(bytes);
1114                    result = bytes;
1115                    break;
1116                case SHORT:
1117                    result = new Short JavaDoc(_in.readShort());
1118                    break;
1119                case CHAR:
1120                    result = new Character JavaDoc(_in.readChar());
1121                    break;
1122                case INT:
1123                    result = new Integer JavaDoc(_in.readInt());
1124                    break;
1125                case LONG:
1126                    result = new Long JavaDoc(_in.readLong());
1127                    break;
1128                case FLOAT:
1129                    result = new Float JavaDoc(_in.readFloat());
1130                    break;
1131                case DOUBLE:
1132                    result = new Double JavaDoc(_in.readDouble());
1133                    break;
1134                case STRING:
1135                    result = _in.readUTF();
1136                    break;
1137            }
1138        } catch (IOException JavaDoc exception) {
1139            raise(exception);
1140        }
1141
1142        return result;
1143    }
1144
1145    /**
1146     * Initialise the input stream if it hasn't been intialised
1147     *
1148     * @return the input stream
1149     */

1150    private DataInputStream JavaDoc getInputStream() {
1151        if (_in == null) {
1152            _byteIn = new ByteArrayInputStream JavaDoc(_bytes, _offset,
1153                _bytes.length - _offset);
1154            _in = new DataInputStream JavaDoc(_byteIn);
1155        }
1156        return _in;
1157    }
1158
1159    /**
1160     * Initialise the output stream if it hasn't been intialised
1161     *
1162     * @return the output stream
1163     * @throws IOException if the output stream can't be created
1164     */

1165    private final DataOutputStream JavaDoc getOutputStream() throws IOException JavaDoc {
1166        if (_out == null) {
1167            _byteOut = new ByteArrayOutputStream JavaDoc();
1168            _out = new DataOutputStream JavaDoc(_byteOut);
1169            _out.write(_bytes);
1170        }
1171        return _out;
1172    }
1173
1174    /**
1175     * Helper to raise a JMSException when an I/O error occurs
1176     *
1177     * @param exception the exception that caused the failure
1178     * @throws JMSException
1179     */

1180    private final void raise(IOException JavaDoc exception) throws JMSException JavaDoc {
1181        JMSException JavaDoc error = null;
1182        if (exception instanceof EOFException JavaDoc) {
1183            error = new MessageEOFException JavaDoc(exception.getMessage());
1184        } else {
1185            error = new JMSException JavaDoc(exception.getMessage());
1186        }
1187        error.setLinkedException(exception);
1188        throw error;
1189    }
1190
1191}
1192
Popular Tags