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 }