View Javadoc

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