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 data) throws 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[] bytes) throws 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 maxLength) throws 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 b) throws JMSException
239 {
240 checkWritable();
241 _changedData = true;
242 _data.put(b ? (byte) 1 : (byte) 0);
243 }
244
245 public void writeByte(byte b) throws JMSException
246 {
247 checkWritable();
248 _changedData = true;
249 _data.put(b);
250 }
251
252 public void writeShort(short i) throws JMSException
253 {
254 checkWritable();
255 _changedData = true;
256 _data.putShort(i);
257 }
258
259 public void writeChar(char c) throws JMSException
260 {
261 checkWritable();
262 _changedData = true;
263 _data.putChar(c);
264 }
265
266 public void writeInt(int i) throws JMSException
267 {
268 checkWritable();
269 _changedData = true;
270 _data.putInt(i);
271 }
272
273 public void writeLong(long l) throws JMSException
274 {
275 checkWritable();
276 _changedData = true;
277 _data.putLong(l);
278 }
279
280 public void writeFloat(float v) throws JMSException
281 {
282 checkWritable();
283 _changedData = true;
284 _data.putFloat(v);
285 }
286
287 public void writeDouble(double v) throws JMSException
288 {
289 checkWritable();
290 _changedData = true;
291 _data.putDouble(v);
292 }
293
294 public void writeUTF(String string) throws 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[] bytes) throws JMSException
318 {
319 checkWritable();
320 _data.put(bytes);
321 _changedData = true;
322 }
323
324 public void writeBytes(byte[] bytes, int offset, int length) throws JMSException
325 {
326 checkWritable();
327 _data.put(bytes, offset, length);
328 _changedData = true;
329 }
330
331 public void writeObject(Object object) throws 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((Byte) object);
342 }
343 else if (clazz == Boolean.class)
344 {
345 writeBoolean((Boolean) object);
346 }
347 else if (clazz == byte[].class)
348 {
349 writeBytes((byte[]) object);
350 }
351 else if (clazz == Short.class)
352 {
353 writeShort((Short) object);
354 }
355 else if (clazz == Character.class)
356 {
357 writeChar((Character) object);
358 }
359 else if (clazz == Integer.class)
360 {
361 writeInt((Integer) object);
362 }
363 else if (clazz == Long.class)
364 {
365 writeLong((Long) object);
366 }
367 else if (clazz == Float.class)
368 {
369 writeFloat((Float) object);
370 }
371 else if (clazz == Double.class)
372 {
373 writeDouble((Double) object);
374 }
375 else if (clazz == String.class)
376 {
377 writeUTF((String) object);
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 }
|