JMSBytesMessage.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  *
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  *
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.client.message;
022 
023 import java.nio.CharBuffer;
024 import java.nio.charset.CharacterCodingException;
025 import java.nio.charset.Charset;
026 import java.nio.charset.CharsetDecoder;
027 import java.nio.charset.CharsetEncoder;
028 
029 import javax.jms.BytesMessage;
030 import javax.jms.JMSException;
031 import javax.jms.MessageFormatException;
032 
033 import org.apache.mina.common.ByteBuffer;
034 import org.apache.qpid.AMQException;
035 import org.apache.qpid.framing.AMQShortString;
036 import org.apache.qpid.framing.BasicContentHeaderProperties;
037 
038 public class JMSBytesMessage extends AbstractBytesMessage implements BytesMessage
039 {
040     public static final String MIME_TYPE = "application/octet-stream";
041 
042 
043 
044     public JMSBytesMessage(AMQMessageDelegateFactory delegateFactory)
045     {
046         this(delegateFactory,null);
047 
048     }
049 
050     /**
051      * Construct a bytes message with existing data.
052      *
053      @param delegateFactory
054      @param data the data that comprises this message. If data is null, you get a 1024 byte buffer that is
055      */
056     JMSBytesMessage(AMQMessageDelegateFactory delegateFactory, ByteBuffer data)
057     {
058 
059         super(delegateFactory, data)// this instanties a content header
060     }
061 
062     JMSBytesMessage(AMQMessageDelegate delegate, ByteBuffer datathrows AMQException
063     {
064         super(delegate, data);
065     }
066 
067 
068     public void reset()
069     {
070         super.reset();
071         _readableMessage = true;
072     }
073 
074     protected String getMimeType()
075     {
076         return MIME_TYPE;
077     }
078 
079     public long getBodyLength() throws JMSException
080     {
081         checkReadable();
082         return _data.limit();
083     }
084 
085     public boolean readBoolean() throws JMSException
086     {
087         checkReadable();
088         checkAvailable(1);
089         return _data.get() != 0;
090     }
091 
092     public byte readByte() throws JMSException
093     {
094         checkReadable();
095         checkAvailable(1);
096         return _data.get();
097     }
098 
099     public int readUnsignedByte() throws JMSException
100     {
101         checkReadable();
102         checkAvailable(1);
103         return _data.getUnsigned();
104     }
105 
106     public short readShort() throws JMSException
107     {
108         checkReadable();
109         checkAvailable(2);
110         return _data.getShort();
111     }
112 
113     public int readUnsignedShort() throws JMSException
114     {
115         checkReadable();
116         checkAvailable(2);
117         return _data.getUnsignedShort();
118     }
119 
120     /**
121      * Note that this method reads a unicode character as two bytes from the stream
122      *
123      @return the character read from the stream
124      @throws JMSException
125      */
126     public char readChar() throws JMSException
127     {
128         checkReadable();
129         checkAvailable(2);
130         return _data.getChar();
131     }
132 
133     public int readInt() throws JMSException
134     {
135         checkReadable();
136         checkAvailable(4);
137         return _data.getInt();
138     }
139 
140     public long readLong() throws JMSException
141     {
142         checkReadable();
143         checkAvailable(8);
144         return _data.getLong();
145     }
146 
147     public float readFloat() throws JMSException
148     {
149         checkReadable();
150         checkAvailable(4);
151         return _data.getFloat();
152     }
153 
154     public double readDouble() throws JMSException
155     {
156         checkReadable();
157         checkAvailable(8);
158         return _data.getDouble();
159     }
160 
161     public String readUTF() throws JMSException
162     {
163         checkReadable();
164         // we check only for one byte since theoretically the string could be only a
165         // single byte when using UTF-8 encoding
166 
167         try
168         {
169             short length = readShort();
170             if(length == 0)
171             {
172                 return "";
173             }
174             else
175             {
176                 CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
177                 ByteBuffer encodedString = _data.slice();
178                 encodedString.limit(length);
179                 _data.position(_data.position()+length);
180                 CharBuffer string = decoder.decode(encodedString.buf());
181                 
182                 return string.toString();
183             }
184 
185 
186             
187         }
188         catch (CharacterCodingException e)
189         {
190             JMSException je = new JMSException("Error decoding byte stream as a UTF8 string: " + e);
191             je.setLinkedException(e);
192             throw je;
193         }
194     }
195 
196     public int readBytes(byte[] bytesthrows JMSException
197     {
198         if (bytes == null)
199         {
200             throw new IllegalArgumentException("byte array must not be null");
201         }
202         checkReadable();
203         int count = (_data.remaining() >= bytes.length ? bytes.length : _data.remaining());
204         if (count == 0)
205         {
206             return -1;
207         }
208         else
209         {
210             _data.get(bytes, 0, count);
211             return count;
212         }
213     }
214 
215     public int readBytes(byte[] bytes, int maxLengththrows JMSException
216     {
217         if (bytes == null)
218         {
219             throw new IllegalArgumentException("byte array must not be null");
220         }
221         if (maxLength > bytes.length)
222         {
223             throw new IllegalArgumentException("maxLength must be <= bytes.length");
224         }
225         checkReadable();
226         int count = (_data.remaining() >= maxLength ? maxLength : _data.remaining());
227         if (count == 0)
228         {
229             return -1;
230         }
231         else
232         {
233             _data.get(bytes, 0, count);
234             return count;
235         }
236     }
237 
238     public void writeBoolean(boolean bthrows JMSException
239     {
240         checkWritable();
241         _changedData = true;
242         _data.put(b ? (byte(byte0);
243     }
244 
245     public void writeByte(byte bthrows JMSException
246     {
247         checkWritable();
248         _changedData = true;
249         _data.put(b);
250     }
251 
252     public void writeShort(short ithrows JMSException
253     {
254         checkWritable();
255         _changedData = true;
256         _data.putShort(i);
257     }
258 
259     public void writeChar(char cthrows JMSException
260     {
261         checkWritable();
262         _changedData = true;
263         _data.putChar(c);
264     }
265 
266     public void writeInt(int ithrows JMSException
267     {
268         checkWritable();
269         _changedData = true;
270         _data.putInt(i);
271     }
272 
273     public void writeLong(long lthrows JMSException
274     {
275         checkWritable();
276         _changedData = true;
277         _data.putLong(l);
278     }
279 
280     public void writeFloat(float vthrows JMSException
281     {
282         checkWritable();
283         _changedData = true;
284         _data.putFloat(v);
285     }
286 
287     public void writeDouble(double vthrows JMSException
288     {
289         checkWritable();
290         _changedData = true;
291         _data.putDouble(v);
292     }
293 
294     public void writeUTF(String stringthrows JMSException
295     {
296         checkWritable();
297         try
298         {
299             CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
300             java.nio.ByteBuffer encodedString = encoder.encode(CharBuffer.wrap(string));
301             
302             _data.putShort((short)encodedString.limit());
303             _data.put(encodedString);
304             _changedData = true;
305             //_data.putString(string, Charset.forName("UTF-8").newEncoder());
306             // we must add the null terminator manually
307             //_data.put((byte)0);
308         }
309         catch (CharacterCodingException e)
310         {
311             JMSException ex = new JMSException("Unable to encode string: " + e);
312             ex.setLinkedException(e);
313             throw ex;
314         }
315     }
316 
317     public void writeBytes(byte[] bytesthrows JMSException
318     {
319         checkWritable();
320         _data.put(bytes);
321         _changedData = true;
322     }
323 
324     public void writeBytes(byte[] bytes, int offset, int lengththrows JMSException
325     {
326         checkWritable();
327         _data.put(bytes, offset, length);
328         _changedData = true;
329     }
330 
331     public void writeObject(Object objectthrows JMSException
332     {
333         checkWritable();
334         if (object == null)
335         {
336             throw new NullPointerException("Argument must not be null");
337         }
338         Class clazz = object.getClass();
339         if (clazz == Byte.class)
340         {
341             writeByte((Byteobject);
342         }
343         else if (clazz == Boolean.class)
344         {
345             writeBoolean((Booleanobject);
346         }
347         else if (clazz == byte[].class)
348         {
349             writeBytes((byte[]) object);
350         }
351         else if (clazz == Short.class)
352         {
353             writeShort((Shortobject);
354         }
355         else if (clazz == Character.class)
356         {
357             writeChar((Characterobject);
358         }
359         else if (clazz == Integer.class)
360         {
361             writeInt((Integerobject);
362         }
363         else if (clazz == Long.class)
364         {
365             writeLong((Longobject);
366         }
367         else if (clazz == Float.class)
368         {
369             writeFloat((Floatobject);
370         }
371         else if (clazz == Double.class)
372         {
373             writeDouble((Doubleobject);
374         }
375         else if (clazz == String.class)
376         {
377             writeUTF((Stringobject);
378         }
379         else
380         {
381             throw new MessageFormatException("Only primitives plus byte arrays and String are valid types");
382         }
383     }
384 
385     public String toString()
386     {
387         return String.valueOf(System.identityHashCode(this));
388     }
389 
390 }