View Javadoc

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-2003 (C) Exoffice Technologies Inc. All Rights Reserved.
42   *
43   * $Id: MessageImpl.java,v 1.21 2003/11/02 11:05:55 tanderson Exp $
44   *
45   * Date         Author  Changes
46   * 02/26/2000   jimm    Created
47   */
48  
49  
50  package org.exolab.jms.message;
51  
52  import java.io.Externalizable;
53  import java.io.IOException;
54  import java.io.ObjectInput;
55  import java.io.ObjectOutput;
56  import java.util.Enumeration;
57  
58  import javax.jms.Destination;
59  import javax.jms.JMSException;
60  import javax.jms.Message;
61  import javax.jms.MessageNotReadableException;
62  import javax.jms.MessageNotWriteableException;
63  
64  import org.exolab.jms.Identifiable;
65  
66  
67  /***
68   * This class implements the javax.jms.Message interface
69   *
70   * @version     $Revision: 1.21 $ $Date: 2003/11/02 11:05:55 $
71   * @author      <a href="mailto:mourikis@exolab.org">Jim Mourikis</a>
72   * @see         javax.jms.Message
73   */
74  public class MessageImpl implements
75      Message, Externalizable, Cloneable, Identifiable {
76  
77      /***
78       * Object version no. for serialization
79       */
80      static final long serialVersionUID = 1;
81  
82      /***
83       * This is a reference to the session that created the message. It
84       * is used for acknowledgment
85       */
86      private MessageSessionIfc _session = null;
87  
88      /***
89       * Contains the message header information as specified by the JMS
90       * specifications
91       */
92      private MessageHeader _messageHeader = new MessageHeader();
93  
94      /***
95       * Holds the properties for the message
96       */
97      private MessageProperties _messageProperties = new MessageProperties();
98  
99      /***
100      * If true, message properties are read-only
101      */
102     protected boolean _propertiesReadOnly = false;
103 
104     /***
105      * If true, the message body is read-only
106      */
107     protected boolean _bodyReadOnly = false;
108 
109     /***
110      * This is the time that the message was accepted by the server
111      */
112     protected long _acceptedTime;
113 
114     /***
115      * This is the sequence number assigned to it by the message
116      * manager when the message is accepted.
117      */
118     protected long _sequenceNumber;
119 
120     /***
121      * This message was received on this connection
122      */
123     protected transient int _connectionId;
124 
125     /***
126      * This flag indicates that the message has been processed by the provider
127      */
128     protected boolean _processed = false;
129 
130     /***
131      * Empty byte array for initialisation purposes
132      */
133     protected static final byte[] EMPTY = new byte[0];
134 
135 
136     /***
137      * Default constructor, required to support externalization
138      */
139     public MessageImpl() {
140     }
141 
142     /***
143      * Clone an instance of this object
144      *
145      * @return a new copy of this object
146      * @throws CloneNotSupportedException if object or attributesare not
147      * cloneable
148      */
149     public Object clone() throws CloneNotSupportedException {
150         MessageImpl result = (MessageImpl) super.clone();
151         result._messageHeader = (MessageHeader) _messageHeader.clone();
152         result._messageProperties =
153             (MessageProperties) _messageProperties.clone();
154         return result;
155     }
156 
157     // implementation of Externalizable.writeExternal
158     public void writeExternal(ObjectOutput out) throws IOException {
159         out.writeLong(serialVersionUID);
160         // the individual read-only states are meaningless when streaming;
161         // they only affect the client when clearProperties or clearBody is
162         // is invoked
163         out.writeBoolean(_propertiesReadOnly || _bodyReadOnly);
164         out.writeBoolean(_processed);
165         out.writeLong(_acceptedTime);
166         out.writeLong(_sequenceNumber);
167         out.writeObject(_messageHeader);
168         out.writeObject(_messageProperties);
169     }
170 
171     // implementation of Externalizable.readExternal
172     public void readExternal(ObjectInput in)
173         throws IOException, ClassNotFoundException {
174         long version = in.readLong();
175         if (version == serialVersionUID) {
176             boolean readOnly = in.readBoolean();
177             _propertiesReadOnly = readOnly;
178             _bodyReadOnly = readOnly;
179             _processed = in.readBoolean();
180             _acceptedTime = in.readLong();
181             _sequenceNumber = in.readLong();
182             _messageHeader = (MessageHeader) in.readObject();
183             _messageProperties = (MessageProperties) in.readObject();
184         } else {
185             throw new IOException("Incorrect version enountered: " +
186                 version + ". This version = " +
187                 serialVersionUID);
188         }
189     }
190 
191     public void setSession(MessageSessionIfc session) {
192         _session = session;
193         MessageId id = _messageHeader.getMessageId();
194         if (id != null) {
195             _messageHeader.setAckMessageID(id.getId());
196         }
197     }
198 
199     public String getJMSMessageID() throws JMSException {
200         return _messageHeader.getJMSMessageID();
201     }
202 
203     public void setJMSMessageID(String id) throws JMSException {
204         _messageHeader.setJMSMessageID(id);
205     }
206 
207     /***
208      * Returns the identifier of the message for acknowledgment.
209      * This will typically be the same as that returned by 
210      * {@link #getJMSMessageID}, unless the message was republished after
211      * its receipt. If the message is republished, this method will return
212      * the original message identifier, whereas {@link #getJMSMessageID} will
213      * return that of the last publication.
214      *
215      * @return the identifier of the message for acknowledgment
216      */
217     public String getAckMessageID() {
218         return _messageHeader.getAckMessageID();
219     }
220 
221 
222     public long getJMSTimestamp() throws JMSException {
223         return _messageHeader.getJMSTimestamp();
224     }
225 
226     public void setJMSTimestamp(long timestamp) throws JMSException {
227         _messageHeader.setJMSTimestamp(timestamp);
228     }
229 
230     /***
231      * Return the wildcard value if there is one.
232      *
233      * @return the wildcard string
234      */
235     public String getWildcard() {
236         return _messageHeader.getWildcard();
237     }
238 
239     /***
240      * Return the message id
241      *
242      * @return MessageId
243      */
244     public MessageId getMessageId() {
245         return _messageHeader.getMessageId();
246     }
247 
248     /***
249      * Set the wildcard string.
250      *
251      * @param wildcard The wildcard.
252      */
253     public void setWildcard(String wildcard) {
254         _messageHeader.setWildcard(wildcard);
255     }
256 
257     /***
258      * Get the value of consumerId
259      *
260      * @return the consumerId
261      */
262     public String getConsumerId() {
263         return _messageHeader.getConsumerId();
264     }
265 
266     /***
267      * Set the value of consumerId
268      *
269      * @param consumerId the consumerId
270      */
271     public void setConsumerId(String consumerId) {
272         _messageHeader.setConsumerId(consumerId);
273     }
274 
275     /***
276      * Get the value of the client session consumer identifier
277      *
278      * @return the value of the client session consumer identifier
279      */
280     public long getClientId() {
281         return _messageHeader.getClientId();
282     }
283 
284     /***
285      * Set the value of the client session consumer identifer
286      *
287      * @param clientId the client session consumer identifier
288      */
289     public void setClientId(long clientId) {
290         _messageHeader.setClientId(clientId);
291     }
292 
293     // Not supported
294     public byte[] getJMSCorrelationIDAsBytes() throws JMSException {
295         return _messageHeader.getJMSCorrelationIDAsBytes();
296     }
297 
298     // Not supported
299     public void setJMSCorrelationIDAsBytes(byte[] correlationID)
300         throws JMSException {
301         _messageHeader.setJMSCorrelationIDAsBytes(correlationID);
302     }
303 
304     public void setJMSCorrelationID(String correlationID) throws JMSException {
305         _messageHeader.setJMSCorrelationID(correlationID);
306     }
307 
308     public String getJMSCorrelationID() throws JMSException {
309         return _messageHeader.getJMSCorrelationID();
310     }
311 
312     public Destination getJMSReplyTo() throws JMSException {
313         return _messageHeader.getJMSReplyTo();
314     }
315 
316     public void setJMSReplyTo(Destination replyTo) throws JMSException {
317         _messageHeader.setJMSReplyTo(replyTo);
318     }
319 
320     public Destination getJMSDestination() throws JMSException {
321         return _messageHeader.getJMSDestination();
322     }
323 
324     public void setJMSDestination(Destination destination)
325         throws JMSException {
326         _messageHeader.setJMSDestination(destination);
327     }
328 
329     public int getJMSDeliveryMode() throws JMSException {
330         return _messageHeader.getJMSDeliveryMode();
331     }
332 
333     public void setJMSDeliveryMode(int deliveryMode) throws JMSException {
334         _messageHeader.setJMSDeliveryMode(deliveryMode);
335     }
336 
337     public boolean getJMSRedelivered() throws JMSException {
338         return _messageHeader.getJMSRedelivered();
339     }
340 
341     public void setJMSRedelivered(boolean redelivered) throws JMSException {
342         _messageHeader.setJMSRedelivered(redelivered);
343     }
344 
345     public String getJMSType() throws JMSException {
346         return _messageHeader.getJMSType();
347     }
348 
349     public void setJMSType(String type) throws JMSException {
350         _messageHeader.setJMSType(type);
351     }
352 
353     public long getJMSExpiration() throws JMSException {
354         return _messageHeader.getJMSExpiration();
355     }
356 
357     public void setJMSExpiration(long expiration) throws JMSException {
358         _messageHeader.setJMSExpiration(expiration);
359     }
360 
361     public int getJMSPriority() throws JMSException {
362         return _messageHeader.getJMSPriority();
363     }
364 
365     public void setJMSPriority(int priority) throws JMSException {
366         _messageHeader.setJMSPriority(priority);
367     }
368 
369     /***
370      * Checks whether the message is persistent.
371      *
372      * @return boolean - true if it is
373      */
374     public boolean isPersistent() {
375         return _messageHeader.isPersistent();
376     }
377 
378     //Expedited or normal
379     public boolean isPriorityExpedited() throws JMSException {
380         return _messageHeader.isPriorityExpedited();
381     }
382 
383     public void clearProperties() throws JMSException {
384         _messageProperties.clearProperties();
385         _propertiesReadOnly = false;
386     }
387 
388     public boolean propertyExists(String name) throws JMSException {
389         return _messageProperties.propertyExists(name);
390     }
391 
392     public boolean getBooleanProperty(String name) throws JMSException {
393         return _messageProperties.getBooleanProperty(name);
394     }
395 
396     public byte getByteProperty(String name) throws JMSException {
397         return _messageProperties.getByteProperty(name);
398     }
399 
400     public short getShortProperty(String name) throws JMSException {
401         return _messageProperties.getShortProperty(name);
402     }
403 
404     public int getIntProperty(String name) throws JMSException {
405         return _messageProperties.getIntProperty(name);
406     }
407 
408     public long getLongProperty(String name) throws JMSException {
409         return _messageProperties.getLongProperty(name);
410     }
411 
412     public float getFloatProperty(String name) throws JMSException {
413         return _messageProperties.getFloatProperty(name);
414     }
415 
416     public double getDoubleProperty(String name) throws JMSException {
417         return _messageProperties.getDoubleProperty(name);
418     }
419 
420     public String getStringProperty(String name) throws JMSException {
421         return _messageProperties.getStringProperty(name);
422     }
423 
424     public Object getObjectProperty(String name) throws JMSException {
425         return _messageProperties.getObjectProperty(name);
426     }
427 
428     public Enumeration getPropertyNames() throws JMSException {
429         return _messageProperties.getPropertyNames();
430     }
431 
432     public void setBooleanProperty(String name, boolean value)
433         throws JMSException {
434         checkPropertyWrite();
435         _messageProperties.setBooleanProperty(name, value);
436     }
437 
438     public void setByteProperty(String name, byte value) throws JMSException {
439         checkPropertyWrite();
440         _messageProperties.setByteProperty(name, value);
441     }
442 
443     public void setShortProperty(String name, short value)
444         throws JMSException {
445         checkPropertyWrite();
446         _messageProperties.setShortProperty(name, value);
447     }
448 
449     public void setIntProperty(String name, int value) throws JMSException {
450         checkPropertyWrite();
451         _messageProperties.setIntProperty(name, value);
452     }
453 
454     public void setLongProperty(String name, long value) throws JMSException {
455         checkPropertyWrite();
456         _messageProperties.setLongProperty(name, value);
457     }
458 
459     public void setFloatProperty(String name, float value)
460         throws JMSException {
461         checkPropertyWrite();
462         _messageProperties.setFloatProperty(name, value);
463     }
464 
465     public void setDoubleProperty(String name, double value)
466         throws JMSException {
467         checkPropertyWrite();
468         _messageProperties.setDoubleProperty(name, value);
469     }
470 
471     public void setStringProperty(String name, String value)
472         throws JMSException {
473         checkPropertyWrite();
474         _messageProperties.setStringProperty(name, value);
475     }
476 
477     public void setObjectProperty(String name, Object value)
478         throws JMSException {
479         checkPropertyWrite();
480         _messageProperties.setObjectProperty(name, value);
481     }
482 
483     /***
484      * Acknowledge the message through the session that dispatched it.
485      * Throw JMSException is there is no session attached to the message
486      *
487      * @throws JMSException if acknowledgement fails
488      */
489     public void acknowledge() throws JMSException {
490         if (getAckMessageID() == null) {
491             throw new JMSException(
492                 "Cannot acknowledge message: no identifier");
493         }
494         if (_session == null) {
495             throw new JMSException(
496                 "Cannot acknowledge message: unknown session");
497         }
498         _session.acknowledgeMessage(this);
499     }
500 
501     public void clearBody() throws JMSException {
502         _bodyReadOnly = false;
503     }
504 
505     public final void checkPropertyWrite()
506         throws MessageNotWriteableException {
507         if (_propertiesReadOnly) {
508             throw new MessageNotWriteableException(
509                 "Message in read-only mode");
510         }
511     }
512 
513     public final void checkWrite() throws MessageNotWriteableException {
514         if (_bodyReadOnly) {
515             throw new MessageNotWriteableException(
516                 "Message in read-only mode");
517         }
518     }
519 
520     public final void checkRead() throws MessageNotReadableException {
521         if (_bodyReadOnly == false) {
522             throw new MessageNotReadableException(
523                 "Message in write-only mode");
524         }
525     }
526 
527     // implementation of Identifiable.getId()
528     public String getId() {
529         return _messageHeader.getMessageId().getId();
530     }
531 
532     /***
533      * Set the time that the message was accepted by the server. This is
534      * different to the JMSTimestamp, which denotes the time that the message
535      * was handed off to the provider.
536      *
537      * @param time the time that the message was accepted by the server
538      */
539     public void setAcceptedTime(long time) {
540         _acceptedTime = time;
541     }
542 
543     /***
544      * Return the time that the messages was accepted by the server
545      *
546      * @return time in milliseconds
547      */
548     public long getAcceptedTime() {
549         return _acceptedTime;
550     }
551 
552     /***
553      * Set the sequence number for this message. Not mandatory.
554      *
555      * @param seq the sequence number, which is used for ordering
556      */
557     public void setSequenceNumber(long seq) {
558         _sequenceNumber = seq;
559     }
560 
561     /***
562      * Return the sequence number associated with this message
563      *
564      * @return the sequence number
565      */
566     public long getSequenceNumber() {
567         return _sequenceNumber;
568     }
569 
570     /***
571      * Set the id of the connection that this message was received on
572      *
573      * @param id the connection id
574      */
575     public void setConnectionId(int id) {
576         _connectionId = id;
577     }
578 
579     /***
580      * Return the id of the connection that this messaged was received on
581      *
582      * @return the connection id
583      */
584     public int getConnectionId() {
585         return _connectionId;
586     }
587 
588     /***
589      * Set the processed state of the message
590      *
591      * @param state true if message has been processed by provider
592      */
593     public void setProcessed(boolean state) {
594         _processed = state;
595     }
596 
597     /***
598      * Check whether the message has been processed
599      *
600      * @return true if the message has been processed
601      */
602     public boolean getProcessed() {
603         return _processed;
604     }
605 
606     /***
607      * Set the read-only state of the message
608      *
609      * @param readOnly if true, make the message body and properties read-only
610      * @throws JMSException if the read-only state cannot be changed
611      */
612     public void setReadOnly(boolean readOnly) throws JMSException {
613         _propertiesReadOnly = readOnly;
614         _bodyReadOnly = readOnly;
615     }
616 
617     /***
618      * Get the read-only state of the message. Note that this only returns true
619      * if both properties and body are read-only
620      *
621      * @return true if the message is read-only
622      */
623     public final boolean getReadOnly() {
624         return _propertiesReadOnly && _bodyReadOnly;
625     }
626 
627     /***
628      * Set the JMSXRcvTimestamp property. This bypasses the read-only
629      * check to avoid unwanted exceptions.
630      */
631     public void setJMSXRcvTimestamp(long timestamp) {
632         _messageProperties.setJMSXRcvTimestamp(timestamp);
633     }
634 
635 } //-- MessageImpl