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.JMSException;
    21  import javax.jms.MessageNotWriteableException;
    22  import javax.jms.TextMessage;
    23  import java.io.DataInput;
    24  import java.io.DataOutput;
    25  import java.io.IOException;
    26  import java.io.UTFDataFormatException;
    27
    28  /***
    29   * A <CODE>TextMessage</CODE> object is used to send a message containing a
    30   * <CODE>java.lang.String</CODE>.
    31   * It inherits from the <CODE>Message</CODE> interface and adds a text message
    32   * body.
    33   * <p/>
    34   * <P>This message type can be used to transport text-based messages, including
    35   * those with XML content.
    36   * <p/>
    37   * <P>When a client receives a <CODE>TextMessage</CODE>, it is in read-only
    38   * mode. If a client attempts to write to the message at this point, a
    39   * <CODE>MessageNotWriteableException</CODE> is thrown. If
    40   * <CODE>clearBody</CODE> is
    41   * called, the message can now be both read from and written to.
    42   *
    43   * @see javax.jms.Session#createTextMessage()
    44   * @see javax.jms.Session#createTextMessage(String)
    45   * @see javax.jms.BytesMessage
    46   * @see javax.jms.MapMessage
    47   * @see javax.jms.Message
    48   * @see javax.jms.ObjectMessage
    49   * @see javax.jms.StreamMessage
    50   * @see java.lang.String
    51   */
    52
    53  public class ActiveMQTextMessage extends ActiveMQMessage implements TextMessage {
    54      private String text;
    55
    56
    57      public String toString() {
    58          String payload = null;
    59          try {
    60              payload = getText();
    61          }
    62          catch (JMSException e) {
    63              payload = "could not read payload: " + e.toString();
    64          }
    65          return super.toString() + ", text = " + payload;
    66      }
    67
    68      /***
    69       * Return the type of Packet
    70       *
    71       * @return integer representation of the type of Packet
    72       */
    73
    74      public int getPacketType() {
    75          return ACTIVEMQ_TEXT_MESSAGE;
    76      }
    77
    78      /***
    79       * @return Returns a shallow copy of the message instance
    80       * @throws JMSException
    81       */
    82
    83      public ActiveMQMessage shallowCopy() throws JMSException {
    84          ActiveMQTextMessage other = new ActiveMQTextMessage();
    85          this.initializeOther(other);
    86          other.text = this.text;
    87          return other;
    88      }
    89
    90      /***
    91       * @return Returns a deep copy of the message - note the header fields are only shallow copied
    92       * @throws JMSException
    93       */
    94
    95      public ActiveMQMessage deepCopy() throws JMSException {
    96          return shallowCopy();
    97      }
    98
    99      /***
    100      * Clears out the message body. Clearing a message's body does not clear
    101      * its header values or property entries.
    102      * <p/>
    103      * <P>If this message body was read-only, calling this method leaves
    104      * the message body in the same state as an empty body in a newly
    105      * created message.
    106      *
    107      * @throws JMSException if the JMS provider fails to clear the message
    108      *                      body due to some internal error.
    109      */
    110
    111     public void clearBody() throws JMSException {
    112         super.clearBody();
    113         this.text = null;
    114     }
    115
    116     /***
    117      * Sets the string containing this message's data.
    118      *
    119      * @param string the <CODE>String</CODE> containing the message's data
    120      * @throws JMSException                 if the JMS provider fails to set the text due to
    121      *                                      some internal error.
    122      * @throws MessageNotWriteableException if the message is in read-only
    123      *                                      mode.
    124      */
    125
    126     public void setText(String string) throws JMSException {
    127         if (super.readOnlyMessage) {
    128             throw new MessageNotWriteableException("The message is read only");
    129         }
    130         this.text = string;
    131     }
    132
    133     void setTextPayload(String string) {
    134         this.text = string;
    135     }
    136
    137
    138     /***
    139      * Gets the string containing this message's data.  The default
    140      * value is null.
    141      *
    142      * @return the <CODE>String</CODE> containing the message's data
    143      * @throws JMSException
    144      */
    145
    146     public String getText() throws JMSException {
    147         if (this.text == null) {
    148             try {
    149                 super.buildBodyFromBytes();
    150             }
    151             catch (IOException ioe) {
    152                 JMSException jmsEx = new JMSException("failed to build body from bytes");
    153                 jmsEx.setLinkedException(ioe);
    154                 throw jmsEx;
    155             }
    156         }
    157         return this.text;
    158     }
    159
    160     /***
    161      * Used serialize the message body to an output stream
    162      *
    163      * @param dataOut
    164      * @throws IOException
    165      */
    166
    167     protected void writeBody(DataOutput dataOut) throws IOException {
    168         if (text != null) {
    169             int strlen = text.length();
    170             int utflen = 0;
    171             char[] charr = new char[strlen];
    172             int c, count = 0;
    173
    174             text.getChars(0, strlen, charr, 0);
    175
    176             for (int i = 0; i < strlen; i++) {
    177                 c = charr[i];
    178                 if ((c >= 0x0001) && (c <= 0x007F)) {
    179                     utflen++;
    180                 }
    181                 else if (c > 0x07FF) {
    182                     utflen += 3;
    183                 }
    184                 else {
    185                     utflen += 2;
    186                 }
    187             }
    188
    189             byte[] bytearr = new byte[utflen + 4];
    190             bytearr[count++] = (byte) ((utflen >>> 24) & 0xFF);
    191             bytearr[count++] = (byte) ((utflen >>> 16) & 0xFF);
    192             bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
    193             bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
    194             for (int i = 0; i < strlen; i++) {
    195                 c = charr[i];
    196                 if ((c >= 0x0001) && (c <= 0x007F)) {
    197                     bytearr[count++] = (byte) c;
    198                 }
    199                 else if (c > 0x07FF) {
    200                     bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
    201                     bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
    202                     bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
    203                 }
    204                 else {
    205                     bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
    206                     bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
    207                 }
    208             }
    209             dataOut.write(bytearr);
    210
    211         }
    212         else {
    213             dataOut.writeInt(-1);
    214         }
    215     }
    216
    217     /***
    218      * Used to help build the body from an input stream
    219      *
    220      * @param dataIn
    221      * @throws IOException
    222      */
    223
    224     protected void readBody(DataInput dataIn) throws IOException {
    225         int utflen = dataIn.readInt();
    226         if (utflen > -1) {
    227             StringBuffer str = new StringBuffer(utflen);
    228             byte bytearr[] = new byte[utflen];
    229             int c, char2, char3;
    230             int count = 0;
    231
    232             dataIn.readFully(bytearr, 0, utflen);
    233
    234             while (count < utflen) {
    235                 c = bytearr[count] & 0xff;
    236                 switch (c >> 4) {
    237                     case 0:
    238                     case 1:
    239                     case 2:
    240                     case 3:
    241                     case 4:
    242                     case 5:
    243                     case 6:
    244                     case 7:
    245                         /* 0xxxxxxx */
    246                         count++;
    247                         str.append((char) c);
    248                         break;
    249                     case 12:
    250                     case 13:
    251                         /* 110x xxxx 10xx xxxx */
    252                         count += 2;
    253                         if (count > utflen) {
    254                             throw new UTFDataFormatException();
    255                         }
    256                         char2 = bytearr[count - 1];
    257                         if ((char2 & 0xC0) != 0x80) {
    258                             throw new UTFDataFormatException();
    259                         }
    260                         str.append((char) (((c & 0x1F) << 6) | (char2 & 0x3F)));
    261                         break;
    262                     case 14:
    263                         /* 1110 xxxx 10xx xxxx 10xx xxxx */
    264                         count += 3;
    265                         if (count > utflen) {
    266                             throw new UTFDataFormatException();
    267                         }
    268                         char2 = bytearr[count - 2];
    269                         char3 = bytearr[count - 1];
    270                         if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) {
    271                             throw new UTFDataFormatException();
    272                         }
    273                         str.append((char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)));
    274                         break;
    275                     default :
    276                         /* 10xx xxxx, 1111 xxxx */
    277                         throw new UTFDataFormatException();
    278                 }
    279             }
    280             // The number of chars produced may be less than utflen
    281             this.text = new String(str);
    282         }
    283     }
    284 }