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         // lets flush the byte memory if available
    131         clearBody();
    132         this.text = string;
    133     }
    134
    135
    136     /***
    137      * Gets the string containing this message's data.  The default
    138      * value is null.
    139      *
    140      * @return the <CODE>String</CODE> containing the message's data
    141      * @throws JMSException
    142      */
    143
    144     public String getText() throws JMSException {
    145         if (this.text == null) {
    146             try {
    147                 super.buildBodyFromBytes();
    148             }
    149             catch (IOException ioe) {
    150                 JMSException jmsEx = new JMSException("failed to build body from bytes");
    151                 jmsEx.setLinkedException(ioe);
    152                 throw jmsEx;
    153             }
    154         }
    155         return this.text;
    156     }
    157
    158     /***
    159      * Used serialize the message body to an output stream
    160      *
    161      * @param dataOut
    162      * @throws IOException
    163      */
    164
    165     protected void writeBody(DataOutput dataOut) throws IOException {
    166         if (text != null) {
    167             int strlen = text.length();
    168             int utflen = 0;
    169             char[] charr = new char[strlen];
    170             int c, count = 0;
    171
    172             text.getChars(0, strlen, charr, 0);
    173
    174             for (int i = 0; i < strlen; i++) {
    175                 c = charr[i];
    176                 if ((c >= 0x0001) && (c <= 0x007F)) {
    177                     utflen++;
    178                 }
    179                 else if (c > 0x07FF) {
    180                     utflen += 3;
    181                 }
    182                 else {
    183                     utflen += 2;
    184                 }
    185             }
    186
    187             byte[] bytearr = new byte[utflen + 4];
    188             bytearr[count++] = (byte) ((utflen >>> 24) & 0xFF);
    189             bytearr[count++] = (byte) ((utflen >>> 16) & 0xFF);
    190             bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
    191             bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
    192             for (int i = 0; i < strlen; i++) {
    193                 c = charr[i];
    194                 if ((c >= 0x0001) && (c <= 0x007F)) {
    195                     bytearr[count++] = (byte) c;
    196                 }
    197                 else if (c > 0x07FF) {
    198                     bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
    199                     bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
    200                     bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
    201                 }
    202                 else {
    203                     bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
    204                     bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
    205                 }
    206             }
    207             dataOut.write(bytearr);
    208
    209         }
    210         else {
    211             dataOut.writeInt(-1);
    212         }
    213     }
    214
    215     /***
    216      * Used to help build the body from an input stream
    217      *
    218      * @param dataIn
    219      * @throws IOException
    220      */
    221
    222     protected void readBody(DataInput dataIn) throws IOException {
    223         int utflen = dataIn.readInt();
    224         if (utflen > -1) {
    225             StringBuffer str = new StringBuffer(utflen);
    226             byte bytearr[] = new byte[utflen];
    227             int c, char2, char3;
    228             int count = 0;
    229
    230             dataIn.readFully(bytearr, 0, utflen);
    231
    232             while (count < utflen) {
    233                 c = bytearr[count] & 0xff;
    234                 switch (c >> 4) {
    235                     case 0:
    236                     case 1:
    237                     case 2:
    238                     case 3:
    239                     case 4:
    240                     case 5:
    241                     case 6:
    242                     case 7:
    243                         /* 0xxxxxxx */
    244                         count++;
    245                         str.append((char) c);
    246                         break;
    247                     case 12:
    248                     case 13:
    249                         /* 110x xxxx 10xx xxxx */
    250                         count += 2;
    251                         if (count > utflen) {
    252                             throw new UTFDataFormatException();
    253                         }
    254                         char2 = bytearr[count - 1];
    255                         if ((char2 & 0xC0) != 0x80) {
    256                             throw new UTFDataFormatException();
    257                         }
    258                         str.append((char) (((c & 0x1F) << 6) | (char2 & 0x3F)));
    259                         break;
    260                     case 14:
    261                         /* 1110 xxxx 10xx xxxx 10xx xxxx */
    262                         count += 3;
    263                         if (count > utflen) {
    264                             throw new UTFDataFormatException();
    265                         }
    266                         char2 = bytearr[count - 2];
    267                         char3 = bytearr[count - 1];
    268                         if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) {
    269                             throw new UTFDataFormatException();
    270                         }
    271                         str.append((char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)));
    272                         break;
    273                     default :
    274                         /* 10xx xxxx, 1111 xxxx */
    275                         throw new UTFDataFormatException();
    276                 }
    277             }
    278             // The number of chars produced may be less than utflen
    279             this.text = new String(str);
    280         }
    281     }
    282 }