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 }