1 /***
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright
7 * statements and notices. Redistributions must also contain a
8 * copy of this document.
9 *
10 * 2. Redistributions in binary form must reproduce the
11 * above copyright notice, this list of conditions and the
12 * following disclaimer in the documentation and/or other
13 * materials provided with the distribution.
14 *
15 * 3. The name "Exolab" must not be used to endorse or promote
16 * products derived from this Software without prior written
17 * permission of Exoffice Technologies. For written permission,
18 * please contact info@exolab.org.
19 *
20 * 4. Products derived from this Software may not be called "Exolab"
21 * nor may "Exolab" appear in their names without prior written
22 * permission of Exoffice Technologies. Exolab is a registered
23 * trademark of Exoffice Technologies.
24 *
25 * 5. Due credit should be given to the Exolab Project
26 * (http://www.exolab.org/).
27 *
28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Copyright 2000-2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: MessageImpl.java,v 1.2 2005/03/18 03:50:12 tanderson Exp $
44 */
45 package org.exolab.jms.message;
46
47 import java.io.Externalizable;
48 import java.io.IOException;
49 import java.io.ObjectInput;
50 import java.io.ObjectOutput;
51 import java.util.Enumeration;
52
53 import javax.jms.Destination;
54 import javax.jms.JMSException;
55 import javax.jms.Message;
56 import javax.jms.MessageNotReadableException;
57 import javax.jms.MessageNotWriteableException;
58
59
60 /***
61 * This class implements the javax.jms.Message interface.
62 *
63 * @version $Revision: 1.2 $ $Date: 2005/03/18 03:50:12 $
64 * @author <a href="mailto:mourikis@exolab.org">Jim Mourikis</a>
65 * @see javax.jms.Message
66 */
67 public class MessageImpl implements
68 Message, Externalizable, Cloneable {
69
70 /***
71 * Object version no. for serialization.
72 */
73 static final long serialVersionUID = 1;
74
75 /***
76 * This is a reference to the session that created the message. It
77 * is used for acknowledgment
78 */
79 private MessageSessionIfc _session = null;
80
81 /***
82 * Contains the message header information as specified by the JMS
83 * specifications.
84 */
85 private MessageHeader _messageHeader = new MessageHeader();
86
87 /***
88 * The message properties
89 */
90 private MessageProperties _messageProperties = new MessageProperties();
91
92 /***
93 * If true, message properties are read-only.
94 */
95 protected boolean _propertiesReadOnly = false;
96
97 /***
98 * If true, the message body is read-only.
99 */
100 protected boolean _bodyReadOnly = false;
101
102 /***
103 * The time that the message was accepted by the server.
104 */
105 protected long _acceptedTime;
106
107 /***
108 * The sequence number assigned to the message by server when the message
109 * is accepted.
110 */
111 protected long _sequenceNumber;
112
113 /***
114 * The identity of the connection that this was received on.
115 */
116 protected transient long _connectionId;
117
118 /***
119 * This flag indicates that the message has been processed by the provider.
120 */
121 protected boolean _processed = false;
122
123 /***
124 * Empty byte array for initialisation purposes.
125 */
126 protected static final byte[] EMPTY = new byte[0];
127
128
129 /***
130 * Default constructor, required to support externalization.
131 */
132 public MessageImpl() {
133 }
134
135 /***
136 * Clone an instance of this object.
137 *
138 * @return a new copy of this object
139 * @throws CloneNotSupportedException if object or attributesare not
140 * cloneable
141 */
142 public Object clone() throws CloneNotSupportedException {
143 MessageImpl result = (MessageImpl) super.clone();
144 result._messageHeader = (MessageHeader) _messageHeader.clone();
145 result._messageProperties =
146 (MessageProperties) _messageProperties.clone();
147 return result;
148 }
149
150
151 public void writeExternal(ObjectOutput out) throws IOException {
152 out.writeLong(serialVersionUID);
153
154
155
156 out.writeBoolean(_propertiesReadOnly || _bodyReadOnly);
157 out.writeBoolean(_processed);
158 out.writeLong(_acceptedTime);
159 out.writeLong(_sequenceNumber);
160 out.writeObject(_messageHeader);
161 out.writeObject(_messageProperties);
162 }
163
164
165 public void readExternal(ObjectInput in)
166 throws IOException, ClassNotFoundException {
167 long version = in.readLong();
168 if (version == serialVersionUID) {
169 boolean readOnly = in.readBoolean();
170 _propertiesReadOnly = readOnly;
171 _bodyReadOnly = readOnly;
172 _processed = in.readBoolean();
173 _acceptedTime = in.readLong();
174 _sequenceNumber = in.readLong();
175 _messageHeader = (MessageHeader) in.readObject();
176 _messageProperties = (MessageProperties) in.readObject();
177 } else {
178 throw new IOException("Incorrect version enountered: " +
179 version + ". This version = " +
180 serialVersionUID);
181 }
182 }
183
184 public void setSession(MessageSessionIfc session) {
185 _session = session;
186 MessageId id = _messageHeader.getMessageId();
187 if (id != null) {
188 _messageHeader.setAckMessageID(id.getId());
189 }
190 }
191
192 public String getJMSMessageID() throws JMSException {
193 return _messageHeader.getJMSMessageID();
194 }
195
196 public void setJMSMessageID(String id) throws JMSException {
197 _messageHeader.setJMSMessageID(id);
198 }
199
200 /***
201 * Returns the identifier of the message for acknowledgment.
202 * This will typically be the same as that returned by
203 * {@link #getJMSMessageID}, unless the message was republished after
204 * its receipt. If the message is republished, this method will return
205 * the original message identifier, whereas {@link #getJMSMessageID} will
206 * return that of the last publication.
207 *
208 * @return the identifier of the message for acknowledgment
209 */
210 public String getAckMessageID() {
211 return _messageHeader.getAckMessageID();
212 }
213
214
215 public long getJMSTimestamp() throws JMSException {
216 return _messageHeader.getJMSTimestamp();
217 }
218
219 public void setJMSTimestamp(long timestamp) throws JMSException {
220 _messageHeader.setJMSTimestamp(timestamp);
221 }
222
223 /***
224 * Return the wildcard value if there is one.
225 *
226 * @return the wildcard string
227 */
228 public String getWildcard() {
229 return _messageHeader.getWildcard();
230 }
231
232 /***
233 * Return the message id
234 *
235 * @return MessageId
236 */
237 public MessageId getMessageId() {
238 return _messageHeader.getMessageId();
239 }
240
241 /***
242 * Set the wildcard string.
243 *
244 * @param wildcard The wildcard.
245 */
246 public void setWildcard(String wildcard) {
247 _messageHeader.setWildcard(wildcard);
248 }
249
250 /***
251 * Returns the value of the consumer identifier
252 *
253 * @return the value of the consumer identifier
254 */
255 public long getConsumerId() {
256 return _messageHeader.getConsumerId();
257 }
258
259 /***
260 * Set the value of the consumer identifer
261 *
262 * @param consumerId the consumer identifier
263 */
264 public void setConsumerId(long consumerId) {
265 _messageHeader.setConsumerId(consumerId);
266 }
267
268
269 public byte[] getJMSCorrelationIDAsBytes() throws JMSException {
270 return _messageHeader.getJMSCorrelationIDAsBytes();
271 }
272
273
274 public void setJMSCorrelationIDAsBytes(byte[] correlationID)
275 throws JMSException {
276 _messageHeader.setJMSCorrelationIDAsBytes(correlationID);
277 }
278
279 public void setJMSCorrelationID(String correlationID) throws JMSException {
280 _messageHeader.setJMSCorrelationID(correlationID);
281 }
282
283 public String getJMSCorrelationID() throws JMSException {
284 return _messageHeader.getJMSCorrelationID();
285 }
286
287 public Destination getJMSReplyTo() throws JMSException {
288 return _messageHeader.getJMSReplyTo();
289 }
290
291 public void setJMSReplyTo(Destination replyTo) throws JMSException {
292 _messageHeader.setJMSReplyTo(replyTo);
293 }
294
295 public Destination getJMSDestination() throws JMSException {
296 return _messageHeader.getJMSDestination();
297 }
298
299 public void setJMSDestination(Destination destination)
300 throws JMSException {
301 _messageHeader.setJMSDestination(destination);
302 }
303
304 public int getJMSDeliveryMode() throws JMSException {
305 return _messageHeader.getJMSDeliveryMode();
306 }
307
308 public void setJMSDeliveryMode(int deliveryMode) throws JMSException {
309 _messageHeader.setJMSDeliveryMode(deliveryMode);
310 }
311
312 public boolean getJMSRedelivered() throws JMSException {
313 return _messageHeader.getJMSRedelivered();
314 }
315
316 public void setJMSRedelivered(boolean redelivered) throws JMSException {
317 _messageHeader.setJMSRedelivered(redelivered);
318 }
319
320 public String getJMSType() throws JMSException {
321 return _messageHeader.getJMSType();
322 }
323
324 public void setJMSType(String type) throws JMSException {
325 _messageHeader.setJMSType(type);
326 }
327
328 public long getJMSExpiration() throws JMSException {
329 return _messageHeader.getJMSExpiration();
330 }
331
332 public void setJMSExpiration(long expiration) throws JMSException {
333 _messageHeader.setJMSExpiration(expiration);
334 }
335
336 public int getJMSPriority() throws JMSException {
337 return _messageHeader.getJMSPriority();
338 }
339
340 public void setJMSPriority(int priority) throws JMSException {
341 _messageHeader.setJMSPriority(priority);
342 }
343
344 public void clearProperties() throws JMSException {
345 _messageProperties.clearProperties();
346 _propertiesReadOnly = false;
347 }
348
349 public boolean propertyExists(String name) throws JMSException {
350 return _messageProperties.propertyExists(name);
351 }
352
353 public boolean getBooleanProperty(String name) throws JMSException {
354 return _messageProperties.getBooleanProperty(name);
355 }
356
357 public byte getByteProperty(String name) throws JMSException {
358 return _messageProperties.getByteProperty(name);
359 }
360
361 public short getShortProperty(String name) throws JMSException {
362 return _messageProperties.getShortProperty(name);
363 }
364
365 public int getIntProperty(String name) throws JMSException {
366 return _messageProperties.getIntProperty(name);
367 }
368
369 public long getLongProperty(String name) throws JMSException {
370 return _messageProperties.getLongProperty(name);
371 }
372
373 public float getFloatProperty(String name) throws JMSException {
374 return _messageProperties.getFloatProperty(name);
375 }
376
377 public double getDoubleProperty(String name) throws JMSException {
378 return _messageProperties.getDoubleProperty(name);
379 }
380
381 public String getStringProperty(String name) throws JMSException {
382 return _messageProperties.getStringProperty(name);
383 }
384
385 public Object getObjectProperty(String name) throws JMSException {
386 return _messageProperties.getObjectProperty(name);
387 }
388
389 public Enumeration getPropertyNames() throws JMSException {
390 return _messageProperties.getPropertyNames();
391 }
392
393 public void setBooleanProperty(String name, boolean value)
394 throws JMSException {
395 checkPropertyWrite();
396 _messageProperties.setBooleanProperty(name, value);
397 }
398
399 public void setByteProperty(String name, byte value) throws JMSException {
400 checkPropertyWrite();
401 _messageProperties.setByteProperty(name, value);
402 }
403
404 public void setShortProperty(String name, short value)
405 throws JMSException {
406 checkPropertyWrite();
407 _messageProperties.setShortProperty(name, value);
408 }
409
410 public void setIntProperty(String name, int value) throws JMSException {
411 checkPropertyWrite();
412 _messageProperties.setIntProperty(name, value);
413 }
414
415 public void setLongProperty(String name, long value) throws JMSException {
416 checkPropertyWrite();
417 _messageProperties.setLongProperty(name, value);
418 }
419
420 public void setFloatProperty(String name, float value)
421 throws JMSException {
422 checkPropertyWrite();
423 _messageProperties.setFloatProperty(name, value);
424 }
425
426 public void setDoubleProperty(String name, double value)
427 throws JMSException {
428 checkPropertyWrite();
429 _messageProperties.setDoubleProperty(name, value);
430 }
431
432 public void setStringProperty(String name, String value)
433 throws JMSException {
434 checkPropertyWrite();
435 _messageProperties.setStringProperty(name, value);
436 }
437
438 public void setObjectProperty(String name, Object value)
439 throws JMSException {
440 checkPropertyWrite();
441 _messageProperties.setObjectProperty(name, value);
442 }
443
444 /***
445 * Acknowledge the message through the session that dispatched it.
446 * Throw JMSException is there is no session attached to the message
447 *
448 * @throws JMSException if acknowledgement fails
449 */
450 public void acknowledge() throws JMSException {
451 if (getAckMessageID() == null) {
452 throw new JMSException(
453 "Cannot acknowledge message: no identifier");
454 }
455 if (_session == null) {
456 throw new JMSException(
457 "Cannot acknowledge message: unknown session");
458 }
459 _session.acknowledgeMessage(this);
460 }
461
462 public void clearBody() throws JMSException {
463 _bodyReadOnly = false;
464 }
465
466 public final void checkPropertyWrite()
467 throws MessageNotWriteableException {
468 if (_propertiesReadOnly) {
469 throw new MessageNotWriteableException(
470 "Message in read-only mode");
471 }
472 }
473
474 public final void checkWrite() throws MessageNotWriteableException {
475 if (_bodyReadOnly) {
476 throw new MessageNotWriteableException(
477 "Message in read-only mode");
478 }
479 }
480
481 public final void checkRead() throws MessageNotReadableException {
482 if (_bodyReadOnly == false) {
483 throw new MessageNotReadableException(
484 "Message in write-only mode");
485 }
486 }
487
488
489 public String getId() {
490 return _messageHeader.getMessageId().getId();
491 }
492
493 /***
494 * Set the time that the message was accepted by the server. This is
495 * different to the JMSTimestamp, which denotes the time that the message
496 * was handed off to the provider.
497 *
498 * @param time the time that the message was accepted by the server
499 */
500 public void setAcceptedTime(long time) {
501 _acceptedTime = time;
502 }
503
504 /***
505 * Return the time that the messages was accepted by the server
506 *
507 * @return time in milliseconds
508 */
509 public long getAcceptedTime() {
510 return _acceptedTime;
511 }
512
513 /***
514 * Set the sequence number for this message. Not mandatory.
515 *
516 * @param seq the sequence number, which is used for ordering
517 */
518 public void setSequenceNumber(long seq) {
519 _sequenceNumber = seq;
520 }
521
522 /***
523 * Return the sequence number associated with this message
524 *
525 * @return the sequence number
526 */
527 public long getSequenceNumber() {
528 return _sequenceNumber;
529 }
530
531 /***
532 * Set the id of the connection that this message was received on
533 *
534 * @param id the connection id
535 */
536 public void setConnectionId(long id) {
537 _connectionId = id;
538 }
539
540 /***
541 * Return the id of the connection that this messaged was received on
542 *
543 * @return the connection id
544 */
545 public long getConnectionId() {
546 return _connectionId;
547 }
548
549 /***
550 * Set the processed state of the message
551 *
552 * @param state true if message has been processed by provider
553 */
554 public void setProcessed(boolean state) {
555 _processed = state;
556 }
557
558 /***
559 * Check whether the message has been processed
560 *
561 * @return true if the message has been processed
562 */
563 public boolean getProcessed() {
564 return _processed;
565 }
566
567 /***
568 * Set the read-only state of the message
569 *
570 * @param readOnly if true, make the message body and properties read-only
571 * @throws JMSException if the read-only state cannot be changed
572 */
573 public void setReadOnly(boolean readOnly) throws JMSException {
574 _propertiesReadOnly = readOnly;
575 _bodyReadOnly = readOnly;
576 }
577
578 /***
579 * Get the read-only state of the message. Note that this only returns true
580 * if both properties and body are read-only
581 *
582 * @return true if the message is read-only
583 */
584 public final boolean getReadOnly() {
585 return _propertiesReadOnly && _bodyReadOnly;
586 }
587
588 /***
589 * Set the JMSXRcvTimestamp property. This bypasses the read-only
590 * check to avoid unwanted exceptions.
591 */
592 public void setJMSXRcvTimestamp(long timestamp) {
593 _messageProperties.setJMSXRcvTimestamp(timestamp);
594 }
595
596 }