View Javadoc

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