001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.activemq.command;
018
019 import java.io.DataInputStream;
020 import java.io.DataOutputStream;
021 import java.io.EOFException;
022 import java.io.FilterOutputStream;
023 import java.io.IOException;
024 import java.io.InputStream;
025 import java.io.OutputStream;
026 import java.util.zip.Deflater;
027 import java.util.zip.DeflaterOutputStream;
028 import java.util.zip.InflaterInputStream;
029
030 import javax.jms.BytesMessage;
031 import javax.jms.JMSException;
032 import javax.jms.MessageFormatException;
033 import javax.jms.MessageNotReadableException;
034
035 import org.apache.activemq.ActiveMQConnection;
036 import org.apache.activemq.util.ByteArrayInputStream;
037 import org.apache.activemq.util.ByteArrayOutputStream;
038 import org.apache.activemq.util.ByteSequence;
039 import org.apache.activemq.util.ByteSequenceData;
040 import org.apache.activemq.util.JMSExceptionSupport;
041
042 /**
043 * A <CODE>BytesMessage</CODE> object is used to send a message containing a
044 * stream of uninterpreted bytes. It inherits from the <CODE>Message</CODE>
045 * interface and adds a bytes message body. The receiver of the message supplies
046 * the interpretation of the bytes.
047 * <P>
048 * The <CODE>BytesMessage</CODE> methods are based largely on those found in
049 * <CODE>java.io.DataInputStream</CODE> and
050 * <CODE>java.io.DataOutputStream</CODE>.
051 * <P>
052 * This message type is for client encoding of existing message formats. If
053 * possible, one of the other self-defining message types should be used
054 * instead.
055 * <P>
056 * Although the JMS API allows the use of message properties with byte messages,
057 * they are typically not used, since the inclusion of properties may affect the
058 * format.
059 * <P>
060 * The primitive types can be written explicitly using methods for each type.
061 * They may also be written generically as objects. For instance, a call to
062 * <CODE>BytesMessage.writeInt(6)</CODE> is equivalent to
063 * <CODE> BytesMessage.writeObject(new Integer(6))</CODE>. Both forms are
064 * provided, because the explicit form is convenient for static programming, and
065 * the object form is needed when types are not known at compile time.
066 * <P>
067 * When the message is first created, and when <CODE>clearBody</CODE> is
068 * called, the body of the message is in write-only mode. After the first call
069 * to <CODE>reset</CODE> has been made, the message body is in read-only mode.
070 * After a message has been sent, the client that sent it can retain and modify
071 * it without affecting the message that has been sent. The same message object
072 * can be sent multiple times. When a message has been received, the provider
073 * has called <CODE>reset</CODE> so that the message body is in read-only mode
074 * for the client.
075 * <P>
076 * If <CODE>clearBody</CODE> is called on a message in read-only mode, the
077 * message body is cleared and the message is in write-only mode.
078 * <P>
079 * If a client attempts to read a message in write-only mode, a
080 * <CODE>MessageNotReadableException</CODE> is thrown.
081 * <P>
082 * If a client attempts to write a message in read-only mode, a
083 * <CODE>MessageNotWriteableException</CODE> is thrown.
084 *
085 * @openwire:marshaller code=24
086 * @see javax.jms.Session#createBytesMessage()
087 * @see javax.jms.MapMessage
088 * @see javax.jms.Message
089 * @see javax.jms.ObjectMessage
090 * @see javax.jms.StreamMessage
091 * @see javax.jms.TextMessage
092 */
093 public class ActiveMQBytesMessage extends ActiveMQMessage implements BytesMessage {
094
095 public static final byte DATA_STRUCTURE_TYPE = CommandTypes.ACTIVEMQ_BYTES_MESSAGE;
096
097 protected transient DataOutputStream dataOut;
098 protected transient ByteArrayOutputStream bytesOut;
099 protected transient DataInputStream dataIn;
100 protected transient int length;
101
102 public Message copy() {
103 ActiveMQBytesMessage copy = new ActiveMQBytesMessage();
104 copy(copy);
105 return copy;
106 }
107
108 private void copy(ActiveMQBytesMessage copy) {
109 storeContent();
110 super.copy(copy);
111 copy.dataOut = null;
112 copy.bytesOut = null;
113 copy.dataIn = null;
114 }
115
116 public void onSend() throws JMSException {
117 super.onSend();
118 storeContent();
119 }
120
121 private void storeContent() {
122 try {
123 if (dataOut != null) {
124 dataOut.close();
125 ByteSequence bs = bytesOut.toByteSequence();
126 if (compressed) {
127 int pos = bs.offset;
128 ByteSequenceData.writeIntBig(bs, length);
129 bs.offset = pos;
130 }
131 setContent(bs);
132 bytesOut = null;
133 dataOut = null;
134 }
135 } catch (IOException ioe) {
136 throw new RuntimeException(ioe.getMessage(), ioe); // TODO verify
137 // RuntimeException
138 }
139 }
140
141 public byte getDataStructureType() {
142 return DATA_STRUCTURE_TYPE;
143 }
144
145 public String getJMSXMimeType() {
146 return "jms/bytes-message";
147 }
148
149 /**
150 * Clears out the message body. Clearing a message's body does not clear its
151 * header values or property entries.
152 * <P>
153 * If this message body was read-only, calling this method leaves the
154 * message body in the same state as an empty body in a newly created
155 * message.
156 *
157 * @throws JMSException if the JMS provider fails to clear the message body
158 * due to some internal error.
159 */
160 public void clearBody() throws JMSException {
161 super.clearBody();
162 this.dataOut = null;
163 this.dataIn = null;
164 this.bytesOut = null;
165 }
166
167 /**
168 * Gets the number of bytes of the message body when the message is in
169 * read-only mode. The value returned can be used to allocate a byte array.
170 * The value returned is the entire length of the message body, regardless
171 * of where the pointer for reading the message is currently located.
172 *
173 * @return number of bytes in the message
174 * @throws JMSException if the JMS provider fails to read the message due to
175 * some internal error.
176 * @throws MessageNotReadableException if the message is in write-only mode.
177 * @since 1.1
178 */
179
180 public long getBodyLength() throws JMSException {
181 initializeReading();
182 return length;
183 }
184
185 /**
186 * Reads a <code>boolean</code> from the bytes message stream.
187 *
188 * @return the <code>boolean</code> value read
189 * @throws JMSException if the JMS provider fails to read the message due to
190 * some internal error.
191 * @throws MessageEOFException if unexpected end of bytes stream has been
192 * reached.
193 * @throws MessageNotReadableException if the message is in write-only mode.
194 */
195 public boolean readBoolean() throws JMSException {
196 initializeReading();
197 try {
198 return this.dataIn.readBoolean();
199 } catch (EOFException e) {
200 throw JMSExceptionSupport.createMessageEOFException(e);
201 } catch (IOException e) {
202 throw JMSExceptionSupport.createMessageFormatException(e);
203 }
204 }
205
206 /**
207 * Reads a signed 8-bit value from the bytes message stream.
208 *
209 * @return the next byte from the bytes message stream as a signed 8-bit
210 * <code>byte</code>
211 * @throws JMSException if the JMS provider fails to read the message due to
212 * some internal error.
213 * @throws MessageEOFException if unexpected end of bytes stream has been
214 * reached.
215 * @throws MessageNotReadableException if the message is in write-only mode.
216 */
217 public byte readByte() throws JMSException {
218 initializeReading();
219 try {
220 return this.dataIn.readByte();
221 } catch (EOFException e) {
222 throw JMSExceptionSupport.createMessageEOFException(e);
223 } catch (IOException e) {
224 throw JMSExceptionSupport.createMessageFormatException(e);
225 }
226 }
227
228 /**
229 * Reads an unsigned 8-bit number from the bytes message stream.
230 *
231 * @return the next byte from the bytes message stream, interpreted as an
232 * unsigned 8-bit number
233 * @throws JMSException if the JMS provider fails to read the message due to
234 * some internal error.
235 * @throws MessageEOFException if unexpected end of bytes stream has been
236 * reached.
237 * @throws MessageNotReadableException if the message is in write-only mode.
238 */
239 public int readUnsignedByte() throws JMSException {
240 initializeReading();
241 try {
242 return this.dataIn.readUnsignedByte();
243 } catch (EOFException e) {
244 throw JMSExceptionSupport.createMessageEOFException(e);
245 } catch (IOException e) {
246 throw JMSExceptionSupport.createMessageFormatException(e);
247 }
248 }
249
250 /**
251 * Reads a signed 16-bit number from the bytes message stream.
252 *
253 * @return the next two bytes from the bytes message stream, interpreted as
254 * a signed 16-bit number
255 * @throws JMSException if the JMS provider fails to read the message due to
256 * some internal error.
257 * @throws MessageEOFException if unexpected end of bytes stream has been
258 * reached.
259 * @throws MessageNotReadableException if the message is in write-only mode.
260 */
261 public short readShort() throws JMSException {
262 initializeReading();
263 try {
264 return this.dataIn.readShort();
265 } catch (EOFException e) {
266 throw JMSExceptionSupport.createMessageEOFException(e);
267 } catch (IOException e) {
268 throw JMSExceptionSupport.createMessageFormatException(e);
269 }
270 }
271
272 /**
273 * Reads an unsigned 16-bit number from the bytes message stream.
274 *
275 * @return the next two bytes from the bytes message stream, interpreted as
276 * an unsigned 16-bit integer
277 * @throws JMSException if the JMS provider fails to read the message due to
278 * some internal error.
279 * @throws MessageEOFException if unexpected end of bytes stream has been
280 * reached.
281 * @throws MessageNotReadableException if the message is in write-only mode.
282 */
283 public int readUnsignedShort() throws JMSException {
284 initializeReading();
285 try {
286 return this.dataIn.readUnsignedShort();
287 } catch (EOFException e) {
288 throw JMSExceptionSupport.createMessageEOFException(e);
289 } catch (IOException e) {
290 throw JMSExceptionSupport.createMessageFormatException(e);
291 }
292 }
293
294 /**
295 * Reads a Unicode character value from the bytes message stream.
296 *
297 * @return the next two bytes from the bytes message stream as a Unicode
298 * character
299 * @throws JMSException if the JMS provider fails to read the message due to
300 * some internal error.
301 * @throws MessageEOFException if unexpected end of bytes stream has been
302 * reached.
303 * @throws MessageNotReadableException if the message is in write-only mode.
304 */
305 public char readChar() throws JMSException {
306 initializeReading();
307 try {
308 return this.dataIn.readChar();
309 } catch (EOFException e) {
310 throw JMSExceptionSupport.createMessageEOFException(e);
311 } catch (IOException e) {
312 throw JMSExceptionSupport.createMessageFormatException(e);
313 }
314 }
315
316 /**
317 * Reads a signed 32-bit integer from the bytes message stream.
318 *
319 * @return the next four bytes from the bytes message stream, interpreted as
320 * an <code>int</code>
321 * @throws JMSException if the JMS provider fails to read the message due to
322 * some internal error.
323 * @throws MessageEOFException if unexpected end of bytes stream has been
324 * reached.
325 * @throws MessageNotReadableException if the message is in write-only mode.
326 */
327 public int readInt() throws JMSException {
328 initializeReading();
329 try {
330 return this.dataIn.readInt();
331 } catch (EOFException e) {
332 throw JMSExceptionSupport.createMessageEOFException(e);
333 } catch (IOException e) {
334 throw JMSExceptionSupport.createMessageFormatException(e);
335 }
336 }
337
338 /**
339 * Reads a signed 64-bit integer from the bytes message stream.
340 *
341 * @return the next eight bytes from the bytes message stream, interpreted
342 * as a <code>long</code>
343 * @throws JMSException if the JMS provider fails to read the message due to
344 * some internal error.
345 * @throws MessageEOFException if unexpected end of bytes stream has been
346 * reached.
347 * @throws MessageNotReadableException if the message is in write-only mode.
348 */
349 public long readLong() throws JMSException {
350 initializeReading();
351 try {
352 return this.dataIn.readLong();
353 } catch (EOFException e) {
354 throw JMSExceptionSupport.createMessageEOFException(e);
355 } catch (IOException e) {
356 throw JMSExceptionSupport.createMessageFormatException(e);
357 }
358 }
359
360 /**
361 * Reads a <code>float</code> from the bytes message stream.
362 *
363 * @return the next four bytes from the bytes message stream, interpreted as
364 * a <code>float</code>
365 * @throws JMSException if the JMS provider fails to read the message due to
366 * some internal error.
367 * @throws MessageEOFException if unexpected end of bytes stream has been
368 * reached.
369 * @throws MessageNotReadableException if the message is in write-only mode.
370 */
371 public float readFloat() throws JMSException {
372 initializeReading();
373 try {
374 return this.dataIn.readFloat();
375 } catch (EOFException e) {
376 throw JMSExceptionSupport.createMessageEOFException(e);
377 } catch (IOException e) {
378 throw JMSExceptionSupport.createMessageFormatException(e);
379 }
380 }
381
382 /**
383 * Reads a <code>double</code> from the bytes message stream.
384 *
385 * @return the next eight bytes from the bytes message stream, interpreted
386 * as a <code>double</code>
387 * @throws JMSException if the JMS provider fails to read the message due to
388 * some internal error.
389 * @throws MessageEOFException if unexpected end of bytes stream has been
390 * reached.
391 * @throws MessageNotReadableException if the message is in write-only mode.
392 */
393 public double readDouble() throws JMSException {
394 initializeReading();
395 try {
396 return this.dataIn.readDouble();
397 } catch (EOFException e) {
398 throw JMSExceptionSupport.createMessageEOFException(e);
399 } catch (IOException e) {
400 throw JMSExceptionSupport.createMessageFormatException(e);
401 }
402 }
403
404 /**
405 * Reads a string that has been encoded using a modified UTF-8 format from
406 * the bytes message stream.
407 * <P>
408 * For more information on the UTF-8 format, see "File System Safe UCS
409 * Transformation Format (FSS_UTF)", X/Open Preliminary Specification,
410 * X/Open Company Ltd., Document Number: P316. This information also appears
411 * in ISO/IEC 10646, Annex P.
412 *
413 * @return a Unicode string from the bytes message stream
414 * @throws JMSException if the JMS provider fails to read the message due to
415 * some internal error.
416 * @throws MessageEOFException if unexpected end of bytes stream has been
417 * reached.
418 * @throws MessageNotReadableException if the message is in write-only mode.
419 */
420 public String readUTF() throws JMSException {
421 initializeReading();
422 try {
423 return this.dataIn.readUTF();
424 } catch (EOFException e) {
425 throw JMSExceptionSupport.createMessageEOFException(e);
426 } catch (IOException e) {
427 throw JMSExceptionSupport.createMessageFormatException(e);
428 }
429 }
430
431 /**
432 * Reads a byte array from the bytes message stream.
433 * <P>
434 * If the length of array <code>value</code> is less than the number of
435 * bytes remaining to be read from the stream, the array should be filled. A
436 * subsequent call reads the next increment, and so on.
437 * <P>
438 * If the number of bytes remaining in the stream is less than the length of
439 * array <code>value</code>, the bytes should be read into the array. The
440 * return value of the total number of bytes read will be less than the
441 * length of the array, indicating that there are no more bytes left to be
442 * read from the stream. The next read of the stream returns -1.
443 *
444 * @param value the buffer into which the data is read
445 * @return the total number of bytes read into the buffer, or -1 if there is
446 * no more data because the end of the stream has been reached
447 * @throws JMSException if the JMS provider fails to read the message due to
448 * some internal error.
449 * @throws MessageNotReadableException if the message is in write-only mode.
450 */
451 public int readBytes(byte[] value) throws JMSException {
452 return readBytes(value, value.length);
453 }
454
455 /**
456 * Reads a portion of the bytes message stream.
457 * <P>
458 * If the length of array <code>value</code> is less than the number of
459 * bytes remaining to be read from the stream, the array should be filled. A
460 * subsequent call reads the next increment, and so on.
461 * <P>
462 * If the number of bytes remaining in the stream is less than the length of
463 * array <code>value</code>, the bytes should be read into the array. The
464 * return value of the total number of bytes read will be less than the
465 * length of the array, indicating that there are no more bytes left to be
466 * read from the stream. The next read of the stream returns -1. <p/> If
467 * <code>length</code> is negative, or <code>length</code> is greater
468 * than the length of the array <code>value</code>, then an
469 * <code>IndexOutOfBoundsException</code> is thrown. No bytes will be read
470 * from the stream for this exception case.
471 *
472 * @param value the buffer into which the data is read
473 * @param length the number of bytes to read; must be less than or equal to
474 * <code>value.length</code>
475 * @return the total number of bytes read into the buffer, or -1 if there is
476 * no more data because the end of the stream has been reached
477 * @throws JMSException if the JMS provider fails to read the message due to
478 * some internal error.
479 * @throws MessageNotReadableException if the message is in write-only mode.
480 */
481 public int readBytes(byte[] value, int length) throws JMSException {
482 initializeReading();
483 try {
484 int n = 0;
485 while (n < length) {
486 int count = this.dataIn.read(value, n, length - n);
487 if (count < 0) {
488 break;
489 }
490 n += count;
491 }
492 if (n == 0 && length > 0) {
493 n = -1;
494 }
495 return n;
496 } catch (EOFException e) {
497 throw JMSExceptionSupport.createMessageEOFException(e);
498 } catch (IOException e) {
499 throw JMSExceptionSupport.createMessageFormatException(e);
500 }
501 }
502
503 /**
504 * Writes a <code>boolean</code> to the bytes message stream as a 1-byte
505 * value. The value <code>true</code> is written as the value
506 * <code>(byte)1</code>; the value <code>false</code> is written as the
507 * value <code>(byte)0</code>.
508 *
509 * @param value the <code>boolean</code> value to be written
510 * @throws JMSException if the JMS provider fails to write the message due
511 * to some internal error.
512 * @throws MessageNotWriteableException if the message is in read-only mode.
513 */
514 public void writeBoolean(boolean value) throws JMSException {
515 initializeWriting();
516 try {
517 this.dataOut.writeBoolean(value);
518 } catch (IOException ioe) {
519 throw JMSExceptionSupport.create(ioe);
520 }
521 }
522
523 /**
524 * Writes a <code>byte</code> to the bytes message stream as a 1-byte
525 * value.
526 *
527 * @param value the <code>byte</code> value to be written
528 * @throws JMSException if the JMS provider fails to write the message due
529 * to some internal error.
530 * @throws MessageNotWriteableException if the message is in read-only mode.
531 */
532 public void writeByte(byte value) throws JMSException {
533 initializeWriting();
534 try {
535 this.dataOut.writeByte(value);
536 } catch (IOException ioe) {
537 throw JMSExceptionSupport.create(ioe);
538 }
539 }
540
541 /**
542 * Writes a <code>short</code> to the bytes message stream as two bytes,
543 * high byte first.
544 *
545 * @param value the <code>short</code> to be written
546 * @throws JMSException if the JMS provider fails to write the message due
547 * to some internal error.
548 * @throws MessageNotWriteableException if the message is in read-only mode.
549 */
550 public void writeShort(short value) throws JMSException {
551 initializeWriting();
552 try {
553 this.dataOut.writeShort(value);
554 } catch (IOException ioe) {
555 throw JMSExceptionSupport.create(ioe);
556 }
557 }
558
559 /**
560 * Writes a <code>char</code> to the bytes message stream as a 2-byte
561 * value, high byte first.
562 *
563 * @param value the <code>char</code> value to be written
564 * @throws JMSException if the JMS provider fails to write the message due
565 * to some internal error.
566 * @throws MessageNotWriteableException if the message is in read-only mode.
567 */
568 public void writeChar(char value) throws JMSException {
569 initializeWriting();
570 try {
571 this.dataOut.writeChar(value);
572 } catch (IOException ioe) {
573 throw JMSExceptionSupport.create(ioe);
574 }
575 }
576
577 /**
578 * Writes an <code>int</code> to the bytes message stream as four bytes,
579 * high byte first.
580 *
581 * @param value the <code>int</code> to be written
582 * @throws JMSException if the JMS provider fails to write the message due
583 * to some internal error.
584 * @throws MessageNotWriteableException if the message is in read-only mode.
585 */
586 public void writeInt(int value) throws JMSException {
587 initializeWriting();
588 try {
589 this.dataOut.writeInt(value);
590 } catch (IOException ioe) {
591 throw JMSExceptionSupport.create(ioe);
592 }
593 }
594
595 /**
596 * Writes a <code>long</code> to the bytes message stream as eight bytes,
597 * high byte first.
598 *
599 * @param value the <code>long</code> to be written
600 * @throws JMSException if the JMS provider fails to write the message due
601 * to some internal error.
602 * @throws MessageNotWriteableException if the message is in read-only mode.
603 */
604 public void writeLong(long value) throws JMSException {
605 initializeWriting();
606 try {
607 this.dataOut.writeLong(value);
608 } catch (IOException ioe) {
609 throw JMSExceptionSupport.create(ioe);
610 }
611 }
612
613 /**
614 * Converts the <code>float</code> argument to an <code>int</code> using
615 * the <code>floatToIntBits</code> method in class <code>Float</code>,
616 * and then writes that <code>int</code> value to the bytes message stream
617 * as a 4-byte quantity, high byte first.
618 *
619 * @param value the <code>float</code> value to be written
620 * @throws JMSException if the JMS provider fails to write the message due
621 * to some internal error.
622 * @throws MessageNotWriteableException if the message is in read-only mode.
623 */
624 public void writeFloat(float value) throws JMSException {
625 initializeWriting();
626 try {
627 this.dataOut.writeFloat(value);
628 } catch (IOException ioe) {
629 throw JMSExceptionSupport.create(ioe);
630 }
631 }
632
633 /**
634 * Converts the <code>double</code> argument to a <code>long</code>
635 * using the <code>doubleToLongBits</code> method in class
636 * <code>Double</code>, and then writes that <code>long</code> value to
637 * the bytes message stream as an 8-byte quantity, high byte first.
638 *
639 * @param value the <code>double</code> value to be written
640 * @throws JMSException if the JMS provider fails to write the message due
641 * to some internal error.
642 * @throws MessageNotWriteableException if the message is in read-only mode.
643 */
644 public void writeDouble(double value) throws JMSException {
645 initializeWriting();
646 try {
647 this.dataOut.writeDouble(value);
648 } catch (IOException ioe) {
649 throw JMSExceptionSupport.create(ioe);
650 }
651 }
652
653 /**
654 * Writes a string to the bytes message stream using UTF-8 encoding in a
655 * machine-independent manner.
656 * <P>
657 * For more information on the UTF-8 format, see "File System Safe UCS
658 * Transformation Format (FSS_UTF)", X/Open Preliminary Specification,
659 * X/Open Company Ltd., Document Number: P316. This information also appears
660 * in ISO/IEC 10646, Annex P.
661 *
662 * @param value the <code>String</code> value to be written
663 * @throws JMSException if the JMS provider fails to write the message due
664 * to some internal error.
665 * @throws MessageNotWriteableException if the message is in read-only mode.
666 */
667 public void writeUTF(String value) throws JMSException {
668 initializeWriting();
669 try {
670 this.dataOut.writeUTF(value);
671 } catch (IOException ioe) {
672 throw JMSExceptionSupport.create(ioe);
673 }
674 }
675
676 /**
677 * Writes a byte array to the bytes message stream.
678 *
679 * @param value the byte array to be written
680 * @throws JMSException if the JMS provider fails to write the message due
681 * to some internal error.
682 * @throws MessageNotWriteableException if the message is in read-only mode.
683 */
684 public void writeBytes(byte[] value) throws JMSException {
685 initializeWriting();
686 try {
687 this.dataOut.write(value);
688 } catch (IOException ioe) {
689 throw JMSExceptionSupport.create(ioe);
690 }
691 }
692
693 /**
694 * Writes a portion of a byte array to the bytes message stream.
695 *
696 * @param value the byte array value to be written
697 * @param offset the initial offset within the byte array
698 * @param length the number of bytes to use
699 * @throws JMSException if the JMS provider fails to write the message due
700 * to some internal error.
701 * @throws MessageNotWriteableException if the message is in read-only mode.
702 */
703 public void writeBytes(byte[] value, int offset, int length) throws JMSException {
704 initializeWriting();
705 try {
706 this.dataOut.write(value, offset, length);
707 } catch (IOException ioe) {
708 throw JMSExceptionSupport.create(ioe);
709 }
710 }
711
712 /**
713 * Writes an object to the bytes message stream.
714 * <P>
715 * This method works only for the objectified primitive object types (<code>Integer</code>,<code>Double</code>,
716 * <code>Long</code> ...), <code>String</code> objects, and byte
717 * arrays.
718 *
719 * @param value the object in the Java programming language ("Java object")
720 * to be written; it must not be null
721 * @throws JMSException if the JMS provider fails to write the message due
722 * to some internal error.
723 * @throws MessageFormatException if the object is of an invalid type.
724 * @throws MessageNotWriteableException if the message is in read-only mode.
725 * @throws java.lang.NullPointerException if the parameter
726 * <code>value</code> is null.
727 */
728 public void writeObject(Object value) throws JMSException {
729 if (value == null) {
730 throw new NullPointerException();
731 }
732 initializeWriting();
733 if (value instanceof Boolean) {
734 writeBoolean(((Boolean)value).booleanValue());
735 } else if (value instanceof Character) {
736 writeChar(((Character)value).charValue());
737 } else if (value instanceof Byte) {
738 writeByte(((Byte)value).byteValue());
739 } else if (value instanceof Short) {
740 writeShort(((Short)value).shortValue());
741 } else if (value instanceof Integer) {
742 writeInt(((Integer)value).intValue());
743 } else if (value instanceof Long) {
744 writeLong(((Long)value).longValue());
745 } else if (value instanceof Float) {
746 writeFloat(((Float)value).floatValue());
747 } else if (value instanceof Double) {
748 writeDouble(((Double)value).doubleValue());
749 } else if (value instanceof String) {
750 writeUTF(value.toString());
751 } else if (value instanceof byte[]) {
752 writeBytes((byte[])value);
753 } else {
754 throw new MessageFormatException("Cannot write non-primitive type:" + value.getClass());
755 }
756 }
757
758 /**
759 * Puts the message body in read-only mode and repositions the stream of
760 * bytes to the beginning.
761 *
762 * @throws JMSException if an internal error occurs
763 */
764 public void reset() throws JMSException {
765 storeContent();
766 this.bytesOut = null;
767 this.dataIn = null;
768 this.dataOut = null;
769 setReadOnlyBody(true);
770 }
771
772 private void initializeWriting() throws JMSException {
773 checkReadOnlyBody();
774 if (this.dataOut == null) {
775 this.bytesOut = new ByteArrayOutputStream();
776 OutputStream os = bytesOut;
777 ActiveMQConnection connection = getConnection();
778 if (connection != null && connection.isUseCompression()) {
779 // keep track of the real length of the content if
780 // we are compressed.
781 try {
782 os.write(new byte[4]);
783 } catch (IOException e) {
784 throw JMSExceptionSupport.create(e);
785 }
786 length = 0;
787 compressed = true;
788 final Deflater deflater = new Deflater(Deflater.BEST_SPEED);
789 os = new FilterOutputStream(new DeflaterOutputStream(os, deflater)) {
790 public void write(byte[] arg0) throws IOException {
791 length += arg0.length;
792 out.write(arg0);
793 }
794
795 public void write(byte[] arg0, int arg1, int arg2) throws IOException {
796 length += arg2;
797 out.write(arg0, arg1, arg2);
798 }
799
800 public void write(int arg0) throws IOException {
801 length++;
802 out.write(arg0);
803 }
804
805 @Override
806 public void close() throws IOException {
807 super.close();
808 deflater.end();
809 }
810 };
811 }
812 this.dataOut = new DataOutputStream(os);
813 }
814 }
815
816 protected void checkWriteOnlyBody() throws MessageNotReadableException {
817 if (!readOnlyBody) {
818 throw new MessageNotReadableException("Message body is write-only");
819 }
820 }
821
822 private void initializeReading() throws JMSException {
823 checkWriteOnlyBody();
824 if (dataIn == null) {
825 ByteSequence data = getContent();
826 if (data == null) {
827 data = new ByteSequence(new byte[] {}, 0, 0);
828 }
829 InputStream is = new ByteArrayInputStream(data);
830 if (isCompressed()) {
831 // keep track of the real length of the content if
832 // we are compressed.
833 try {
834 DataInputStream dis = new DataInputStream(is);
835 length = dis.readInt();
836 dis.close();
837 } catch (IOException e) {
838 throw JMSExceptionSupport.create(e);
839 }
840 is = new InflaterInputStream(is);
841 } else {
842 length = data.getLength();
843 }
844 dataIn = new DataInputStream(is);
845 }
846 }
847
848 public void setObjectProperty(String name, Object value) throws JMSException {
849 initializeWriting();
850 super.setObjectProperty(name, value);
851 }
852
853 public String toString() {
854 return super.toString() + " ActiveMQBytesMessage{ " + "bytesOut = " + bytesOut + ", dataOut = " + dataOut + ", dataIn = " + dataIn + " }";
855 }
856 }