Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/activemq/message/ActiveMQMessage.java


1   /**
2    * 
3    * Copyright 2004 Protique Ltd
4    * 
5    * Licensed under the Apache License, Version 2.0 (the "License"); 
6    * you may not use this file except in compliance with the License. 
7    * You may obtain a copy of the License at 
8    * 
9    * http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License. 
16   * 
17   **/
18  
19  package org.activemq.message;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.DataInput;
24  import java.io.DataInputStream;
25  import java.io.DataOutput;
26  import java.io.DataOutputStream;
27  import java.io.IOException;
28  import java.util.Collections;
29  import java.util.Enumeration;
30  import java.util.HashMap;
31  import java.util.Iterator;
32  import java.util.Map;
33  import java.util.List;
34  import java.util.ArrayList;
35  import java.util.StringTokenizer;
36  
37  import javax.jms.DeliveryMode;
38  import javax.jms.Destination;
39  import javax.jms.JMSException;
40  import javax.jms.Message;
41  import javax.jms.MessageFormatException;
42  import javax.jms.MessageNotWriteableException;
43  
44  import org.activemq.io.util.ByteArray;
45  import org.activemq.io.util.ByteArrayCompression;
46  import org.activemq.io.util.MemoryManageable;
47  import org.activemq.service.MessageIdentity;
48  import org.activemq.util.IdGenerator;
49  
50  /**
51   * The <CODE>Message</CODE> interface is the root interface of all JMS
52   * messages. It defines the message header and the <CODE>acknowledge</CODE>
53   * method used for all messages.
54   * <p/>
55   * <P>Most message-oriented middleware (MOM) products treat messages as
56   * lightweight entities that consist
57   * of a header and a payload. The header contains fields used for message
58   * routing and identification; the payload contains the application data
59   * being sent.
60   * <p/>
61   * <P>Within this general form, the definition of a message varies
62   * significantly across products. It would be quite difficult for the JMS API
63   * to support all of these message models.
64   * <p/>
65   * <P>With this in mind, the JMS message model has the following goals:
66   * <UL>
67   * <LI>Provide a single, unified message API
68   * <LI>Provide an API suitable for creating messages that match the
69   * format used by provider-native messaging applications
70   * <LI>Support the development of heterogeneous applications that span
71   * operating systems, machine architectures, and computer languages
72   * <LI>Support messages containing objects in the Java programming language
73   * ("Java objects")
74   * <LI>Support messages containing Extensible Markup Language (XML) pages
75   * </UL>
76   * <p/>
77   * <P>JMS messages are composed of the following parts:
78   * <UL>
79   * <LI>Header - All messages support the same set of header fields.
80   * Header fields contain values used by both clients and providers to
81   * identify and route messages.
82   * <LI>Properties - Each message contains a built-in facility for supporting
83   * application-defined property values. Properties provide an efficient
84   * mechanism for supporting application-defined message filtering.
85   * <LI>Body - The JMS API defines several types of message body, which cover
86   * the majority of messaging styles currently in use.
87   * </UL>
88   * <p/>
89   * <H4>Message Bodies</H4>
90   * <p/>
91   * <P>The JMS API defines five types of message body:
92   * <UL>
93   * <LI>Stream - A <CODE>StreamMessage</CODE> object's message body contains
94   * a stream of primitive values in the Java programming
95   * language ("Java primitives"). It is filled and read sequentially.
96   * <LI>Map - A <CODE>MapMessage</CODE> object's message body contains a set
97   * of name-value pairs, where names are <CODE>String</CODE>
98   * objects, and values are Java primitives. The entries can be accessed
99   * sequentially or randomly by name. The order of the entries is
100  * undefined.
101  * <LI>Text - A <CODE>TextMessage</CODE> object's message body contains a
102  * <CODE>java.lang.String</CODE> object. This message type can be used
103  * to transport plain-text messages, and XML messages.
104  * <LI>Object - An <CODE>ObjectMessage</CODE> object's message body contains
105  * a <CODE>Serializable</CODE> Java object.
106  * <LI>Bytes - A <CODE>BytesMessage</CODE> object's message body contains a
107  * stream of uninterpreted bytes. This message type is for
108  * literally encoding a body to match an existing message format. In
109  * many cases, it is possible to use one of the other body types,
110  * which are easier to use. Although the JMS API allows the use of
111  * message properties with byte messages, they are typically not used,
112  * since the inclusion of properties may affect the format.
113  * </UL>
114  * <p/>
115  * <H4>Message Headers</H4>
116  * <p/>
117  * <P>The <CODE>JMSCorrelationID</CODE> header field is used for linking one
118  * message with
119  * another. It typically links a reply message with its requesting message.
120  * <p/>
121  * <P><CODE>JMSCorrelationID</CODE> can hold a provider-specific message ID,
122  * an application-specific <CODE>String</CODE> object, or a provider-native
123  * <CODE>byte[]</CODE> value.
124  * <p/>
125  * <H4>Message Properties</H4>
126  * <p/>
127  * <P>A <CODE>Message</CODE> object contains a built-in facility for supporting
128  * application-defined property values. In effect, this provides a mechanism
129  * for adding application-specific header fields to a message.
130  * <p/>
131  * <P>Properties allow an application, via message selectors, to have a JMS
132  * provider select, or filter, messages on its behalf using
133  * application-specific criteria.
134  * <p/>
135  * <P>Property names must obey the rules for a message selector identifier.
136  * Property names must not be null, and must not be empty strings. If a property
137  * name is set and it is either null or an empty string, an
138  * <CODE>IllegalArgumentException</CODE> must be thrown.
139  * <p/>
140  * <P>Property values can be <CODE>boolean</CODE>, <CODE>byte</CODE>,
141  * <CODE>short</CODE>, <CODE>int</CODE>, <CODE>long</CODE>, <CODE>float</CODE>,
142  * <CODE>double</CODE>, and <CODE>String</CODE>.
143  * <p/>
144  * <P>Property values are set prior to sending a message. When a client
145  * receives a message, its properties are in read-only mode. If a
146  * client attempts to set properties at this point, a
147  * <CODE>MessageNotWriteableException</CODE> is thrown. If
148  * <CODE>clearProperties</CODE> is called, the properties can now be both
149  * read from and written to. Note that header fields are distinct from
150  * properties. Header fields are never in read-only mode.
151  * <p/>
152  * <P>A property value may duplicate a value in a message's body, or it may
153  * not. Although JMS does not define a policy for what should or should not
154  * be made a property, application developers should note that JMS providers
155  * will likely handle data in a message's body more efficiently than data in
156  * a message's properties. For best performance, applications should use
157  * message properties only when they need to customize a message's header.
158  * The primary reason for doing this is to support customized message
159  * selection.
160  * <p/>
161  * <P>Message properties support the following conversion table. The marked
162  * cases must be supported. The unmarked cases must throw a
163  * <CODE>JMSException</CODE>. The <CODE>String</CODE>-to-primitive conversions
164  * may throw a runtime exception if the
165  * primitive's <CODE>valueOf</CODE> method does not accept the
166  * <CODE>String</CODE> as a valid representation of the primitive.
167  * <p/>
168  * <P>A value written as the row type can be read as the column type.
169  * <p/>
170  * <PRE>
171  * |        | boolean byte short int long float double String
172  * |----------------------------------------------------------
173  * |boolean |    X                                       X
174  * |byte    |          X     X    X   X                  X
175  * |short   |                X    X   X                  X
176  * |int     |                     X   X                  X
177  * |long    |                         X                  X
178  * |float   |                               X     X      X
179  * |double  |                                     X      X
180  * |String  |    X     X     X    X   X     X     X      X
181  * |----------------------------------------------------------
182  * </PRE>
183  * <p/>
184  * <P>In addition to the type-specific set/get methods for properties, JMS
185  * provides the <CODE>setObjectProperty</CODE> and
186  * <CODE>getObjectProperty</CODE> methods. These support the same set of
187  * property types using the objectified primitive values. Their purpose is
188  * to allow the decision of property type to made at execution time rather
189  * than at compile time. They support the same property value conversions.
190  * <p/>
191  * <P>The <CODE>setObjectProperty</CODE> method accepts values of class
192  * <CODE>Boolean</CODE>, <CODE>Byte</CODE>, <CODE>Short</CODE>,
193  * <CODE>Integer</CODE>, <CODE>Long</CODE>, <CODE>Float</CODE>,
194  * <CODE>Double</CODE>, and <CODE>String</CODE>. An attempt
195  * to use any other class must throw a <CODE>JMSException</CODE>.
196  * <p/>
197  * <P>The <CODE>getObjectProperty</CODE> method only returns values of class
198  * <CODE>Boolean</CODE>, <CODE>Byte</CODE>, <CODE>Short</CODE>,
199  * <CODE>Integer</CODE>, <CODE>Long</CODE>, <CODE>Float</CODE>,
200  * <CODE>Double</CODE>, and <CODE>String</CODE>.
201  * <p/>
202  * <P>The order of property values is not defined. To iterate through a
203  * message's property values, use <CODE>getPropertyNames</CODE> to retrieve
204  * a property name enumeration and then use the various property get methods
205  * to retrieve their values.
206  * <p/>
207  * <P>A message's properties are deleted by the <CODE>clearProperties</CODE>
208  * method. This leaves the message with an empty set of properties.
209  * <p/>
210  * <P>Getting a property value for a name which has not been set returns a
211  * null value. Only the <CODE>getStringProperty</CODE> and
212  * <CODE>getObjectProperty</CODE> methods can return a null value.
213  * Attempting to read a null value as a primitive type must be treated as
214  * calling the primitive's corresponding <CODE>valueOf(String)</CODE>
215  * conversion method with a null value.
216  * <p/>
217  * <P>The JMS API reserves the <CODE>JMSX</CODE> property name prefix for JMS
218  * defined properties.
219  * The full set of these properties is defined in the Java Message Service
220  * specification. New JMS defined properties may be added in later versions
221  * of the JMS API.  Support for these properties is optional. The
222  * <CODE>String[] ConnectionMetaData.getJMSXPropertyNames</CODE> method
223  * returns the names of the JMSX properties supported by a connection.
224  * <p/>
225  * <P>JMSX properties may be referenced in message selectors whether or not
226  * they are supported by a connection. If they are not present in a
227  * message, they are treated like any other absent property.
228  * <p/>
229  * <P>JMSX properties defined in the specification as "set by provider on
230  * send" are available to both the producer and the consumers of the message.
231  * JMSX properties defined in the specification as "set by provider on
232  * receive" are available only to the consumers.
233  * <p/>
234  * <P><CODE>JMSXGroupID</CODE> and <CODE>JMSXGroupSeq</CODE> are standard
235  * properties that clients
236  * should use if they want to group messages. All providers must support them.
237  * Unless specifically noted, the values and semantics of the JMSX properties
238  * are undefined.
239  * <p/>
240  * <P>The JMS API reserves the <CODE>JMS_<I>vendor_name</I></CODE> property
241  * name prefix for provider-specific properties. Each provider defines its own
242  * value for <CODE><I>vendor_name</I></CODE>. This is the mechanism a JMS
243  * provider uses to make its special per-message services available to a JMS
244  * client.
245  * <p/>
246  * <P>The purpose of provider-specific properties is to provide special
247  * features needed to integrate JMS clients with provider-native clients in a
248  * single JMS application. They should not be used for messaging between JMS
249  * clients.
250  * <p/>
251  * <H4>Provider Implementations of JMS Message Interfaces</H4>
252  * <p/>
253  * <P>The JMS API provides a set of message interfaces that define the JMS
254  * message
255  * model. It does not provide implementations of these interfaces.
256  * <p/>
257  * <P>Each JMS provider supplies a set of message factories with its
258  * <CODE>Session</CODE> object for creating instances of messages. This allows
259  * a provider to use message implementations tailored to its specific needs.
260  * <p/>
261  * <P>A provider must be prepared to accept message implementations that are
262  * not its own. They may not be handled as efficiently as its own
263  * implementation; however, they must be handled.
264  * <p/>
265  * <P>Note the following exception case when a provider is handling a foreign
266  * message implementation. If the foreign message implementation contains a
267  * <CODE>JMSReplyTo</CODE> header field that is set to a foreign destination
268  * implementation, the provider is not required to handle or preserve the
269  * value of this header field.
270  * <p/>
271  * <H4>Message Selectors</H4>
272  * <p/>
273  * <P>A JMS message selector allows a client to specify, by
274  * header field references and property references, the
275  * messages it is interested in. Only messages whose header
276  * and property values
277  * match the
278  * selector are delivered. What it means for a message not to be delivered
279  * depends on the <CODE>MessageConsumer</CODE> being used (see
280  * {@link javax.jms.QueueReceiver QueueReceiver} and
281  * {@link javax.jms.TopicSubscriber TopicSubscriber}).
282  * <p/>
283  * <P>Message selectors cannot reference message body values.
284  * <p/>
285  * <P>A message selector matches a message if the selector evaluates to
286  * true when the message's header field values and property values are
287  * substituted for their corresponding identifiers in the selector.
288  * <p/>
289  * <P>A message selector is a <CODE>String</CODE> whose syntax is based on a
290  * subset of
291  * the SQL92 conditional expression syntax. If the value of a message selector
292  * is an empty string, the value is treated as a null and indicates that there
293  * is no message selector for the message consumer.
294  * <p/>
295  * <P>The order of evaluation of a message selector is from left to right
296  * within precedence level. Parentheses can be used to change this order.
297  * <p/>
298  * <P>Predefined selector literals and operator names are shown here in
299  * uppercase; however, they are case insensitive.
300  * <p/>
301  * <P>A selector can contain:
302  * <p/>
303  * <UL>
304  * <LI>Literals:
305  * <UL>
306  * <LI>A string literal is enclosed in single quotes, with a single quote
307  * represented by doubled single quote; for example,
308  * <CODE>'literal'</CODE> and <CODE>'literal''s'</CODE>. Like
309  * string literals in the Java programming language, these use the
310  * Unicode character encoding.
311  * <LI>An exact numeric literal is a numeric value without a decimal
312  * point, such as <CODE>57</CODE>, <CODE>-957</CODE>, and
313  * <CODE>+62</CODE>; numbers in the range of <CODE>long</CODE> are
314  * supported. Exact numeric literals use the integer literal
315  * syntax of the Java programming language.
316  * <LI>An approximate numeric literal is a numeric value in scientific
317  * notation, such as <CODE>7E3</CODE> and <CODE>-57.9E2</CODE>, or a
318  * numeric value with a decimal, such as <CODE>7.</CODE>,
319  * <CODE>-95.7</CODE>, and <CODE>+6.2</CODE>; numbers in the range of
320  * <CODE>double</CODE> are supported. Approximate literals use the
321  * floating-point literal syntax of the Java programming language.
322  * <LI>The boolean literals <CODE>TRUE</CODE> and <CODE>FALSE</CODE>.
323  * </UL>
324  * <LI>Identifiers:
325  * <UL>
326  * <LI>An identifier is an unlimited-length sequence of letters
327  * and digits, the first of which must be a letter. A letter is any
328  * character for which the method <CODE>Character.isJavaLetter</CODE>
329  * returns true. This includes <CODE>'_'</CODE> and <CODE>'$'</CODE>.
330  * A letter or digit is any character for which the method
331  * <CODE>Character.isJavaLetterOrDigit</CODE> returns true.
332  * <LI>Identifiers cannot be the names <CODE>NULL</CODE>,
333  * <CODE>TRUE</CODE>, and <CODE>FALSE</CODE>.
334  * <LI>Identifiers cannot be <CODE>NOT</CODE>, <CODE>AND</CODE>,
335  * <CODE>OR</CODE>, <CODE>BETWEEN</CODE>, <CODE>LIKE</CODE>,
336  * <CODE>IN</CODE>, <CODE>IS</CODE>, or <CODE>ESCAPE</CODE>.
337  * <LI>Identifiers are either header field references or property
338  * references.  The type of a property value in a message selector
339  * corresponds to the type used to set the property. If a property
340  * that does not exist in a message is referenced, its value is
341  * <CODE>NULL</CODE>.
342  * <LI>The conversions that apply to the get methods for properties do not
343  * apply when a property is used in a message selector expression.
344  * For example, suppose you set a property as a string value, as in the
345  * following:
346  * <PRE>myMessage.setStringProperty("NumberOfOrders", "2");</PRE>
347  * The following expression in a message selector would evaluate to
348  * false, because a string cannot be used in an arithmetic expression:
349  * <PRE>"NumberOfOrders > 1"</PRE>
350  * <LI>Identifiers are case-sensitive.
351  * <LI>Message header field references are restricted to
352  * <CODE>JMSDeliveryMode</CODE>, <CODE>JMSPriority</CODE>,
353  * <CODE>JMSMessageID</CODE>, <CODE>JMSTimestamp</CODE>,
354  * <CODE>JMSCorrelationID</CODE>, and <CODE>JMSType</CODE>.
355  * <CODE>JMSMessageID</CODE>, <CODE>JMSCorrelationID</CODE>, and
356  * <CODE>JMSType</CODE> values may be null and if so are treated as a
357  * <CODE>NULL</CODE> value.
358  * <LI>Any name beginning with <CODE>'JMSX'</CODE> is a JMS defined
359  * property name.
360  * <LI>Any name beginning with <CODE>'JMS_'</CODE> is a provider-specific
361  * property name.
362  * <LI>Any name that does not begin with <CODE>'JMS'</CODE> is an
363  * application-specific property name.
364  * </UL>
365  * <LI>White space is the same as that defined for the Java programming
366  * language: space, horizontal tab, form feed, and line terminator.
367  * <LI>Expressions:
368  * <UL>
369  * <LI>A selector is a conditional expression; a selector that evaluates
370  * to <CODE>true</CODE> matches; a selector that evaluates to
371  * <CODE>false</CODE> or unknown does not match.
372  * <LI>Arithmetic expressions are composed of themselves, arithmetic
373  * operations, identifiers (whose value is treated as a numeric
374  * literal), and numeric literals.
375  * <LI>Conditional expressions are composed of themselves, comparison
376  * operations, and logical operations.
377  * </UL>
378  * <LI>Standard bracketing <CODE>()</CODE> for ordering expression evaluation
379  * is supported.
380  * <LI>Logical operators in precedence order: <CODE>NOT</CODE>,
381  * <CODE>AND</CODE>, <CODE>OR</CODE>
382  * <LI>Comparison operators: <CODE>=</CODE>, <CODE>></CODE>, <CODE>>=</CODE>,
383  * <CODE><</CODE>, <CODE><=</CODE>, <CODE><></CODE> (not equal)
384  * <UL>
385  * <LI>Only like type values can be compared. One exception is that it
386  * is valid to compare exact numeric values and approximate numeric
387  * values; the type conversion required is defined by the rules of
388  * numeric promotion in the Java programming language. If the
389  * comparison of non-like type values is attempted, the value of the
390  * operation is false. If either of the type values evaluates to
391  * <CODE>NULL</CODE>, the value of the expression is unknown.
392  * <LI>String and boolean comparison is restricted to <CODE>=</CODE> and
393  * <CODE><></CODE>. Two strings are equal
394  * if and only if they contain the same sequence of characters.
395  * </UL>
396  * <LI>Arithmetic operators in precedence order:
397  * <UL>
398  * <LI><CODE>+</CODE>, <CODE>-</CODE> (unary)
399  * <LI><CODE>*</CODE>, <CODE>/</CODE> (multiplication and division)
400  * <LI><CODE>+</CODE>, <CODE>-</CODE> (addition and subtraction)
401  * <LI>Arithmetic operations must use numeric promotion in the Java
402  * programming language.
403  * </UL>
404  * <LI><CODE><I>arithmetic-expr1</I> [NOT] BETWEEN <I>arithmetic-expr2</I>
405  * AND <I>arithmetic-expr3</I></CODE> (comparison operator)
406  * <UL>
407  * <LI><CODE>"age&nbsp;BETWEEN&nbsp;15&nbsp;AND&nbsp;19"</CODE> is
408  * equivalent to
409  * <CODE>"age&nbsp;>=&nbsp;15&nbsp;AND&nbsp;age&nbsp;<=&nbsp;19"</CODE>
410  * <LI><CODE>"age&nbsp;NOT&nbsp;BETWEEN&nbsp;15&nbsp;AND&nbsp;19"</CODE>
411  * is equivalent to
412  * <CODE>"age&nbsp;<&nbsp;15&nbsp;OR&nbsp;age&nbsp;>&nbsp;19"</CODE>
413  * </UL>
414  * <LI><CODE><I>identifier</I> [NOT] IN (<I>string-literal1</I>,
415  * <I>string-literal2</I>,...)</CODE> (comparison operator where
416  * <CODE><I>identifier</I></CODE> has a <CODE>String</CODE> or
417  * <CODE>NULL</CODE> value)
418  * <UL>
419  * <LI><CODE>"Country&nbsp;IN&nbsp;('&nbsp;UK',&nbsp;'US',&nbsp;'France')"</CODE>
420  * is true for
421  * <CODE>'UK'</CODE> and false for <CODE>'Peru'</CODE>; it is
422  * equivalent to the expression
423  * <CODE>"(Country&nbsp;=&nbsp;'&nbsp;UK')&nbsp;OR&nbsp;(Country&nbsp;=&nbsp;'&nbsp;US')&nbsp;OR&nbsp;(Country&nbsp;=&nbsp;'&nbsp;France')"</CODE>
424  * <LI><CODE>"Country&nbsp;NOT&nbsp;IN&nbsp;('&nbsp;UK',&nbsp;'US',&nbsp;'France')"</CODE>
425  * is false for <CODE>'UK'</CODE> and true for <CODE>'Peru'</CODE>; it
426  * is equivalent to the expression
427  * <CODE>"NOT&nbsp;((Country&nbsp;=&nbsp;'&nbsp;UK')&nbsp;OR&nbsp;(Country&nbsp;=&nbsp;'&nbsp;US')&nbsp;OR&nbsp;(Country&nbsp;=&nbsp;'&nbsp;France'))"</CODE>
428  * <LI>If identifier of an <CODE>IN</CODE> or <CODE>NOT IN</CODE>
429  * operation is <CODE>NULL</CODE>, the value of the operation is
430  * unknown.
431  * </UL>
432  * <LI><CODE><I>identifier</I> [NOT] LIKE <I>pattern-value</I> [ESCAPE
433  * <I>escape-character</I>]</CODE> (comparison operator, where
434  * <CODE><I>identifier</I></CODE> has a <CODE>String</CODE> value;
435  * <CODE><I>pattern-value</I></CODE> is a string literal where
436  * <CODE>'_'</CODE> stands for any single character; <CODE>'%'</CODE>
437  * stands for any sequence of characters, including the empty sequence;
438  * and all other characters stand for themselves. The optional
439  * <CODE><I>escape-character</I></CODE> is a single-character string
440  * literal whose character is used to escape the special meaning of the
441  * <CODE>'_'</CODE> and <CODE>'%'</CODE> in
442  * <CODE><I>pattern-value</I></CODE>.)
443  * <UL>
444  * <LI><CODE>"phone&nbsp;LIKE&nbsp;'12%3'"</CODE> is true for
445  * <CODE>'123'</CODE> or <CODE>'12993'</CODE> and false for
446  * <CODE>'1234'</CODE>
447  * <LI><CODE>"word&nbsp;LIKE&nbsp;'l_se'"</CODE> is true for
448  * <CODE>'lose'</CODE> and false for <CODE>'loose'</CODE>
449  * <LI><CODE>"underscored&nbsp;LIKE&nbsp;'\_%'&nbsp;ESCAPE&nbsp;'\'"</CODE>
450  * is true for <CODE>'_foo'</CODE> and false for <CODE>'bar'</CODE>
451  * <LI><CODE>"phone&nbsp;NOT&nbsp;LIKE&nbsp;'12%3'"</CODE> is false for
452  * <CODE>'123'</CODE> or <CODE>'12993'</CODE> and true for
453  * <CODE>'1234'</CODE>
454  * <LI>If <CODE><I>identifier</I></CODE> of a <CODE>LIKE</CODE> or
455  * <CODE>NOT LIKE</CODE> operation is <CODE>NULL</CODE>, the value
456  * of the operation is unknown.
457  * </UL>
458  * <LI><CODE><I>identifier</I> IS NULL</CODE> (comparison operator that tests
459  * for a null header field value or a missing property value)
460  * <UL>
461  * <LI><CODE>"prop_name&nbsp;IS&nbsp;NULL"</CODE>
462  * </UL>
463  * <LI><CODE><I>identifier</I> IS NOT NULL</CODE> (comparison operator that
464  * tests for the existence of a non-null header field value or a property
465  * value)
466  * <UL>
467  * <LI><CODE>"prop_name&nbsp;IS&nbsp;NOT&nbsp;NULL"</CODE>
468  * </UL>
469  * <p/>
470  * <P>JMS providers are required to verify the syntactic correctness of a
471  * message selector at the time it is presented. A method that provides a
472  * syntactically incorrect selector must result in a <CODE>JMSException</CODE>.
473  * JMS providers may also optionally provide some semantic checking at the time
474  * the selector is presented. Not all semantic checking can be performed at
475  * the time a message selector is presented, because property types are not known.
476  * <p/>
477  * <P>The following message selector selects messages with a message type
478  * of car and color of blue and weight greater than 2500 pounds:
479  * <p/>
480  * <PRE>"JMSType&nbsp;=&nbsp;'car'&nbsp;AND&nbsp;color&nbsp;=&nbsp;'blue'&nbsp;AND&nbsp;weight&nbsp;>&nbsp;2500"</PRE>
481  * <p/>
482  * <H4>Null Values</H4>
483  * <p/>
484  * <P>As noted above, property values may be <CODE>NULL</CODE>. The evaluation
485  * of selector expressions containing <CODE>NULL</CODE> values is defined by
486  * SQL92 <CODE>NULL</CODE> semantics. A brief description of these semantics
487  * is provided here.
488  * <p/>
489  * <P>SQL treats a <CODE>NULL</CODE> value as unknown. Comparison or arithmetic
490  * with an unknown value always yields an unknown value.
491  * <p/>
492  * <P>The <CODE>IS NULL</CODE> and <CODE>IS NOT NULL</CODE> operators convert
493  * an unknown value into the respective <CODE>TRUE</CODE> and
494  * <CODE>FALSE</CODE> values.
495  * <p/>
496  * <P>The boolean operators use three-valued logic as defined by the
497  * following tables:
498  * <p/>
499  * <P><B>The definition of the <CODE>AND</CODE> operator</B>
500  * <p/>
501  * <PRE>
502  * | AND  |   T   |   F   |   U
503  * +------+-------+-------+-------
504  * |  T   |   T   |   F   |   U
505  * |  F   |   F   |   F   |   F
506  * |  U   |   U   |   F   |   U
507  * +------+-------+-------+-------
508  * </PRE>
509  * <p/>
510  * <P><B>The definition of the <CODE>OR</CODE> operator</B>
511  * <p/>
512  * <PRE>
513  * | OR   |   T   |   F   |   U
514  * +------+-------+-------+--------
515  * |  T   |   T   |   T   |   T
516  * |  F   |   T   |   F   |   U
517  * |  U   |   T   |   U   |   U
518  * +------+-------+-------+-------
519  * </PRE>
520  * <p/>
521  * <P><B>The definition of the <CODE>NOT</CODE> operator</B>
522  * <p/>
523  * <PRE>
524  * | NOT
525  * +------+------
526  * |  T   |   F
527  * |  F   |   T
528  * |  U   |   U
529  * +------+-------
530  * </PRE>
531  * <p/>
532  * <H4>Special Notes</H4>
533  * <p/>
534  * <P>When used in a message selector, the <CODE>JMSDeliveryMode</CODE> header
535  * field is treated as having the values <CODE>'PERSISTENT'</CODE> and
536  * <CODE>'NON_PERSISTENT'</CODE>.
537  * <p/>
538  * <P>Date and time values should use the standard <CODE>long</CODE>
539  * millisecond value. When a date or time literal is included in a message
540  * selector, it should be an integer literal for a millisecond value. The
541  * standard way to produce millisecond values is to use
542  * <CODE>java.util.Calendar</CODE>.
543  * <p/>
544  * <P>Although SQL supports fixed decimal comparison and arithmetic, JMS
545  * message selectors do not. This is the reason for restricting exact
546  * numeric literals to those without a decimal (and the addition of
547  * numerics with a decimal as an alternate representation for
548  * approximate numeric values).
549  * <p/>
550  * <P>SQL comments are not supported.
551  *
552  * @version $Revision: 1.1.1.1 $
553  * @see javax.jms.MessageConsumer#receive()
554  * @see javax.jms.MessageConsumer#receive(long)
555  * @see javax.jms.MessageConsumer#receiveNoWait()
556  * @see javax.jms.MessageListener#onMessage(Message)
557  * @see javax.jms.BytesMessage
558  * @see javax.jms.MapMessage
559  * @see javax.jms.ObjectMessage
560  * @see javax.jms.StreamMessage
561  * @see javax.jms.TextMessage
562  */
563 
564 public class ActiveMQMessage extends AbstractPacket implements Message, Comparable, MemoryManageable, BodyPacket {
565 
566     /**
567      * The message producer's default delivery mode is <CODE>PERSISTENT</CODE>.
568      *
569      * @see DeliveryMode#PERSISTENT
570      */
571     static final int DEFAULT_DELIVERY_MODE = DeliveryMode.PERSISTENT;
572 
573     /**
574      * The message producer's default priority is 4.
575      */
576     static final int DEFAULT_PRIORITY = 4;
577 
578     /**
579      * The message producer's default time to live is unlimited; the message
580      * never expires.
581      */
582     static final long DEFAULT_TIME_TO_LIVE = 0;
583 
584     /**
585      * message property types
586      */
587     final static byte EOF = 2;
588     final static byte BYTES = 3;
589     final static byte STRING = 4;
590     final static byte BOOLEAN = 5;
591     final static byte CHAR = 6;
592     final static byte BYTE = 7;
593     final static byte SHORT = 8;
594     final static byte INT = 9;
595     final static byte LONG = 10;
596     final static byte FLOAT = 11;
597     final static byte DOUBLE = 12;
598     final static byte NULL = 13;
599 
600     /**
601      * Message flag indexes (used for writing/reading to/from a Stream
602      */
603     
604     public static final int CORRELATION_INDEX = 2;
605     public static final int TYPE_INDEX = 3;
606     public static final int BROKER_NAME_INDEX = 4;
607     public static final int CLUSTER_NAME_INDEX = 5;
608     public static final int TRANSACTION_ID_INDEX = 6;
609     public static final int REPLY_TO_INDEX = 7;
610     public static final int TIMESTAMP_INDEX = 8;
611     public static final int EXPIRATION_INDEX = 9;
612     public static final int REDELIVERED_INDEX = 10;
613     public static final int XA_TRANS_INDEX = 11;
614     public static final int CID_INDEX = 12;
615     public static final int PROPERTIES_INDEX = 13;
616     public static final int DISPATCHED_FROM_DLQ_INDEX = 14;
617     public static final int PAYLOAD_INDEX = 15;
618     public static final int EXTERNAL_MESSAGE_ID_INDEX = 16;
619     public static final int MESSAGE_PART_INDEX = 17;
620     public static final int CACHED_VALUES_INDEX = 18;
621     public static final int CACHED_DESTINATION_INDEX = 19;
622     public static final int LONG_SEQUENCE_INDEX = 20;
623     
624 
625 
626     private static final String DELIVERY_COUNT_NAME = "JMSXDeliveryCount";
627     /**
628      * <code>readOnlyMessage</code> denotes if the message is read only
629      */
630     protected boolean readOnlyMessage;
631 
632     private String jmsMessageID;
633     private String jmsClientID;
634     private String jmsCorrelationID;
635     private String producerKey;
636     private ActiveMQDestination jmsDestination;
637     private ActiveMQDestination jmsReplyTo;
638     private int jmsDeliveryMode = DEFAULT_DELIVERY_MODE;
639     private boolean jmsRedelivered;
640     private String jmsType;
641     private long jmsExpiration;
642     private int jmsPriority = DEFAULT_PRIORITY;
643     private long jmsTimestamp;
644     private Map properties;
645     private boolean readOnlyProperties;
646     private String entryBrokerName;
647     private String entryClusterName;
648     private int[] consumerNos; //these are set by the broker, and only relevant to consuming connections
649     private Object transactionId;
650     private boolean xaTransacted;
651     private String consumerIdentifier; //this is only used on the Client for acknowledging receipt of a message
652     private boolean messageConsumed;//only used on the client - to denote if its been delivered and read
653     private boolean transientConsumed;//only used on the client - to denote if its been delivered and read
654     private long sequenceNumber;//the sequence for this message from the producerId
655     private int deliveryCount = 1;//number of times the message has been delivered
656     private boolean dispatchedFromDLQ;
657     private MessageAcknowledge messageAcknowledge;
658     private ByteArray bodyAsBytes;
659     private MessageIdentity jmsMessageIdentity;
660     private short messsageHandle;//refers to the id of the MessageProducer that sent the message
661     private boolean externalMessageId;//is the messageId set from another JMS implementation ?
662     private boolean messagePart;//is the message split into multiple packets
663     private short numberOfParts;
664     private short partNumber;
665     private String parentMessageID;//if split into multiple parts - the 'real' or first messageId
666 
667 
668     /**
669      * Retrieve if a JMS Message type or not
670      *
671      * @return true if it is a JMS Message
672      */
673     public boolean isJMSMessage() {
674         return true;
675     }
676 
677 
678     /**
679      * @return pretty print of this Message
680      */
681     public String toString() {
682         return super.toString() + " ActiveMQMessage{ " +
683                 ", jmsMessageID = " + jmsMessageID +
684                 ", bodyAsBytes = " + bodyAsBytes +
685                 ", readOnlyMessage = " + readOnlyMessage +
686                 ", jmsClientID = '" + jmsClientID + "' " +
687                 ", jmsCorrelationID = '" + jmsCorrelationID + "' " +
688                 ", jmsDestination = " + jmsDestination +
689                 ", jmsReplyTo = " + jmsReplyTo +
690                 ", jmsDeliveryMode = " + jmsDeliveryMode +
691                 ", jmsRedelivered = " + jmsRedelivered +
692                 ", jmsType = '" + jmsType + "' " +
693                 ", jmsExpiration = " + jmsExpiration +
694                 ", jmsPriority = " + jmsPriority +
695                 ", jmsTimestamp = " + jmsTimestamp +
696                 ", properties = " + properties +
697                 ", readOnlyProperties = " + readOnlyProperties +
698                 ", entryBrokerName = '" + entryBrokerName + "' " +
699                 ", entryClusterName = '" + entryClusterName + "' " +
700                 ", consumerNos = " + toString(consumerNos) +
701                 ", transactionId = '" + transactionId + "' " +
702                 ", xaTransacted = " + xaTransacted +
703                 ", consumerIdentifer = '" + consumerIdentifier + "' " +
704                 ", messageConsumed = " + messageConsumed +
705                 ", transientConsumed = " + transientConsumed +
706                 ", sequenceNumber = " + sequenceNumber +
707                 ", deliveryCount = " + deliveryCount +
708                 ", dispatchedFromDLQ = " + dispatchedFromDLQ +
709                 ", messageAcknowledge = " + messageAcknowledge +
710                 ", jmsMessageIdentity = " + jmsMessageIdentity +
711                 ", producerKey = " + producerKey + 
712                 " }";
713     }
714 
715     protected String toString(int[] consumerNos) {
716         if (consumerNos == null) {
717             return "null";
718         }
719         StringBuffer buffer = new StringBuffer("[");
720         for (int i = 0; i < consumerNos.length; i++) {
721             int consumerNo = consumerNos[i];
722             if (i > 0) {
723                 buffer.append(", ");
724             }
725             buffer.append(Integer.toString(i));
726         }
727         buffer.append("]");
728         return buffer.toString();
729     }
730 
731 
732     /**
733      * @return Returns the messageAcknowledge.
734      *
735      * @Transient
736      */
737     public MessageAcknowledge getMessageAcknowledge() {
738         return messageAcknowledge;
739     }
740 
741     /**
742      * @param messageAcknowledge The messageAcknowledge to set.
743      */
744     public void setMessageAcknowledge(MessageAcknowledge messageAcknowledge) {
745         this.messageAcknowledge = messageAcknowledge;
746     }
747 
748     /**
749      * Return the type of Packet
750      *
751      * @return integer representation of the type of Packet
752      */
753 
754     public int getPacketType() {
755         return ACTIVEMQ_MESSAGE;
756     }
757 
758 
759     /**
760      * set the message readOnly
761      *
762      * @param value
763      */
764     public void setReadOnly(boolean value) {
765         this.readOnlyProperties = value;
766         this.readOnlyMessage = value;
767     }
768 
769     /**
770      * test to see if a particular Consumer at a Connection
771      * is meant to receive this Message
772      *
773      * @param consumerNumber
774      * @return true if a target
775      */
776 
777     public boolean isConsumerTarget(int consumerNumber) {
778         if (consumerNos != null) {
779             for (int i = 0; i < consumerNos.length; i++) {
780                 if (consumerNos[i] == consumerNumber) {
781                     return true;
782                 }
783             }
784         }
785         return false;
786     }
787 
788     /**
789      * @return consumer Nos as a String
790      */
791     public String getConsumerNosAsString() {
792         String result = "";
793         if (consumerNos != null) {
794             for (int i = 0; i < consumerNos.length; i++) {
795                 if (i > 0) {
796                     result += ",";
797                 }
798                 result += consumerNos[i];
799             }
800         }
801         return result;
802     }
803 
804     /**
805      * Sets the consumer numbers using a String format
806      */
807     public void setConsumerNosAsString(String value) {
808         if (value == null) {
809             setConsumerNos(null);
810         }
811         else {
812             List values = new ArrayList();
813             StringTokenizer enm = new StringTokenizer(value, ",");
814             while (enm.hasMoreElements()) {
815                 String token = enm.nextToken();
816                 values.add(token);
817             }
818 
819             int[] answer = new int[values.size()];
820             int i = 0;
821             for (Iterator iter = values.iterator(); iter.hasNext();) {
822                 String text = (String) iter.next();
823                 answer[i++] = Integer.parseInt(text.trim());
824             }
825             setConsumerNos(answer);
826         }
827     }
828 
829 
830     /**
831      * @return true if the message is non-persistent or intended for a temporary destination
832      */
833     public boolean isTemporary() {
834         return jmsDeliveryMode == DeliveryMode.NON_PERSISTENT ||
835                 (jmsDestination != null && jmsDestination.isTemporary());
836     }
837 
838     /**
839      * @return Returns hash code for this instance
840      */
841 
842     public int hashCode() {
843         return this.getJMSMessageID() != null ? this.getJMSMessageID().hashCode() : super.hashCode();
844     }
845 
846     /**
847      * Returns true if this instance is equivalent to obj
848      *
849      * @param obj the other instance to test
850      * @return true/false
851      */
852 
853     public boolean equals(Object obj) {
854         boolean result = obj == this;
855         if (!result && obj != null && obj instanceof ActiveMQMessage) {
856             ActiveMQMessage other = (ActiveMQMessage) obj;
857             //the call getJMSMessageID() will initialize the messageID
858             //if it hasn't already been set
859             result = this.getJMSMessageID() == other.getJMSMessageID();
860             if (!result){
861                 if (this.jmsMessageID != null && this.jmsMessageID.length() > 0 ||
862                         other.jmsMessageID != null && other.jmsMessageID.length() > 0){
863                     if (this.jmsMessageID != null && other.jmsMessageID != null){
864                         result = this.jmsMessageID.equals(other.jmsMessageID);
865                     }
866                 }else{
867                     result = this.getId() == other.getId();
868                 }
869             }
870         }
871         return result;
872     }
873 
874     /**
875      * @param o object to compare
876      * @return 1 if this > o else 0 if they are equal or -1 if this < o
877      */
878     public int compareTo(Object o) {
879         if (o instanceof ActiveMQMessage) {
880             return compareTo((ActiveMQMessage) o);
881         }
882         return -1;
883     }
884 
885     /**
886      * Sorted by destination and then messageId
887      *
888      * @param that another message to compare against
889      * @return 1 if this > that else 0 if they are equal or -1 if this < that
890      */
891     public int compareTo(ActiveMQMessage that) {
892         int answer = 1;
893 
894         if (that != null && this.jmsDestination != null && that.jmsDestination != null) {
895             answer = this.jmsDestination.compareTo(that.jmsDestination);
896             if (answer == 0) {
897                 if (this.jmsMessageID != null && that.jmsMessageID != null) {
898                     answer = IdGenerator.compare(this.jmsMessageID, that.jmsMessageID);
899                 }
900                 else {
901                     answer = 1;
902                 }
903             }
904         }
905         return answer;
906     }
907 
908 
909     /**
910      * @return Returns a shallow copy of the message instance
911      * @throws JMSException
912      */
913 
914     public ActiveMQMessage shallowCopy() throws JMSException {
915         ActiveMQMessage other = new ActiveMQMessage();
916         this.initializeOther(other);
917         return other;
918     }
919 
920     /**
921      * @return Returns a deep copy of the message - note the header fields are only shallow copied
922      * @throws JMSException
923      */
924 
925     public ActiveMQMessage deepCopy() throws JMSException {
926         return shallowCopy();
927     }
928 
929 
930     /**
931      * Indicates if the Message has expired
932      *
933      * @param currentTime -
934      *                    the current time in milliseconds
935      * @return true if the message can be expired
936      */
937     public boolean isExpired(long currentTime) {
938         boolean result = false;
939         long expiration = this.jmsExpiration;
940         if (jmsExpiration > 0 && jmsExpiration < currentTime) {
941             result = true;
942         }
943         return result;
944     }
945 
946     /**
947      * @return true if the message is expired
948      */
949     public boolean isExpired() {
950         return !dispatchedFromDLQ && jmsExpiration > 0 && isExpired(System.currentTimeMillis());
951     }
952     
953     /**
954      * @return true if an advisory message
955      */
956     public boolean isAdvisory(){
957         return jmsDestination != null && jmsDestination.isAdvisory();
958     }
959 
960     /**
961      * Initializes another message with current values from this instance
962      *
963      * @param other the other ActiveMQMessage to initialize
964      */
965     protected void initializeOther(ActiveMQMessage other) {
966         super.initializeOther(other);
967         other.jmsMessageID = this.jmsMessageID;
968         other.jmsClientID = this.jmsClientID;
969         other.jmsCorrelationID = this.jmsCorrelationID;
970         other.jmsDestination = this.jmsDestination;
971         other.jmsReplyTo = this.jmsReplyTo;
972         other.jmsDeliveryMode = this.jmsDeliveryMode;
973         other.jmsRedelivered = this.jmsRedelivered;
974         other.jmsType = this.jmsType;
975         other.jmsExpiration = this.jmsExpiration;
976         other.jmsPriority = this.jmsPriority;
977         other.jmsTimestamp = this.jmsTimestamp;
978         other.properties = this.properties != null ? new HashMap(this.properties) : null;
979         other.readOnlyProperties = this.readOnlyProperties;
980         other.readOnlyMessage = this.readOnlyMessage;
981         other.entryBrokerName = this.entryBrokerName;
982         other.entryClusterName = this.entryClusterName;
983         other.consumerNos = this.consumerNos;
984         other.transactionId = this.transactionId;
985         other.xaTransacted = this.xaTransacted;
986         other.bodyAsBytes = this.bodyAsBytes;
987         other.messageAcknowledge = this.messageAcknowledge;
988         other.jmsMessageIdentity = this.jmsMessageIdentity;
989         other.sequenceNumber = this.sequenceNumber;
990         other.deliveryCount = this.deliveryCount;
991         other.dispatchedFromDLQ = this.dispatchedFromDLQ;
992         other.messsageHandle = this.messsageHandle;
993         other.consumerIdentifier = this.consumerIdentifier;
994         other.externalMessageId = this.externalMessageId;
995         other.producerKey = this.producerKey;
996         other.messagePart = this.messagePart;
997         other.numberOfParts = this.numberOfParts;
998         other.partNumber = this.partNumber;
999         other.parentMessageID = this.parentMessageID;
1000    }
1001    
1002
1003    /**
1004     * Gets the message ID.
1005     * <p/>
1006     * <P>The <CODE>JMSMessageID</CODE> header field contains a value that
1007     * uniquely identifies each message sent by a provider.
1008     * <p/>
1009     * <P>When a message is sent, <CODE>JMSMessageID</CODE> can be ignored.
1010     * When the <CODE>send</CODE> or <CODE>publish</CODE> method returns, it
1011     * contains a provider-assigned value.
1012     * <p/>
1013     * <P>A <CODE>JMSMessageID</CODE> is a <CODE>String</CODE> value that
1014     * should function as a
1015     * unique key for identifying messages in a historical repository.
1016     * The exact scope of uniqueness is provider-defined. It should at
1017     * least cover all messages for a specific installation of a
1018     * provider, where an installation is some connected set of message
1019     * routers.
1020     * <p/>
1021     * <P>All <CODE>JMSMessageID</CODE> values must start with the prefix
1022     * <CODE>'ID:'</CODE>.
1023     * Uniqueness of message ID values across different providers is
1024     * not required.
1025     * <p/>
1026     * <P>Since message IDs take some effort to create and increase a
1027     * message's size, some JMS providers may be able to optimize message
1028     * overhead if they are given a hint that the message ID is not used by
1029     * an application. By calling the
1030     * <CODE>MessageProducer.setDisableMessageID</CODE> method, a JMS client
1031     * enables this potential optimization for all messages sent by that
1032     * message producer. If the JMS provider accepts this
1033     * hint, these messages must have the message ID set to null; if the
1034     * provider ignores the hint, the message ID must be set to its normal
1035     * unique value.
1036     *
1037     * @return the message ID
1038     * @see javax.jms.Message#setJMSMessageID(String)
1039     * @see javax.jms.MessageProducer#setDisableMessageID(boolean)
1040     */
1041
1042    public String getJMSMessageID() {
1043        if (jmsMessageID == null && producerKey != null){
1044            jmsMessageID = producerKey + sequenceNumber;
1045        }
1046        return jmsMessageID;
1047    }
1048
1049
1050    /**
1051     * Sets the message ID.
1052     * <p/>
1053     * <P>JMS providers set this field when a message is sent. This method
1054     * can be used to change the value for a message that has been received.
1055     *
1056     * @param id the ID of the message
1057     * @see javax.jms.Message#getJMSMessageID()
1058     */
1059
1060    public void setJMSMessageID(String id) {
1061        this.jmsMessageID = id;
1062        this.jmsMessageIdentity = null;
1063    }
1064
1065    /**
1066     * Another way to get the Message id. 
1067     *
1068     * @Transient
1069     */
1070    public Object getMemoryId() {
1071        return getJMSMessageID();
1072    }
1073
1074    /**
1075     * Gets the message timestamp.
1076     * <p/>
1077     * <P>The <CODE>JMSTimestamp</CODE> header field contains the time a
1078     * message was
1079     * handed off to a provider to be sent. It is not the time the
1080     * message was actually transmitted, because the actual send may occur
1081     * later due to transactions or other client-side queueing of messages.
1082     * <p/>
1083     * <P>When a message is sent, <CODE>JMSTimestamp</CODE> is ignored. When
1084     * the <CODE>send</CODE> or <CODE>publish</CODE>
1085     * method returns, it contains a time value somewhere in the interval
1086     * between the call and the return. The value is in the format of a normal
1087     * millis time value in the Java programming language.
1088     * <p/>
1089     * <P>Since timestamps take some effort to create and increase a
1090     * message's size, some JMS providers may be able to optimize message
1091     * overhead if they are given a hint that the timestamp is not used by an
1092     * application. By calling the
1093     * <CODE>MessageProducer.setDisableMessageTimestamp</CODE> method, a JMS
1094     * client enables this potential optimization for all messages sent by
1095     * that message producer. If the JMS provider accepts this
1096     * hint, these messages must have the timestamp set to zero; if the
1097     * provider ignores the hint, the timestamp must be set to its normal
1098     * value.
1099     *
1100     * @return the message timestamp
1101     * @see javax.jms.Message#setJMSTimestamp(long)
1102     * @see javax.jms.MessageProducer#setDisableMessageTimestamp(boolean)
1103     */
1104
1105    public long getJMSTimestamp() {
1106        return jmsTimestamp;
1107    }
1108
1109
1110    /**
1111     * Sets the message timestamp.
1112     * <p/>
1113     * <P>JMS providers set this field when a message is sent. This method
1114     * can be used to change the value for a message that has been received.
1115     *
1116     * @param timestamp the timestamp for this message
1117     * @see javax.jms.Message#getJMSTimestamp()
1118     */
1119
1120    public void setJMSTimestamp(long timestamp) {
1121        this.jmsTimestamp = timestamp;
1122    }
1123
1124
1125    /**
1126     * Gets the correlation ID as an array of bytes for the message.
1127     * <p/>
1128     * <P>The use of a <CODE>byte[]</CODE> value for
1129     * <CODE>JMSCorrelationID</CODE> is non-portable.
1130     *
1131     * @return the correlation ID of a message as an array of bytes
1132     * @see javax.jms.Message#setJMSCorrelationID(String)
1133     * @see javax.jms.Message#getJMSCorrelationID()
1134     * @see javax.jms.Message#setJMSCorrelationIDAsBytes(byte[])
1135     *
1136     * @Transient
1137     */
1138    public byte[] getJMSCorrelationIDAsBytes() {
1139        return this.jmsCorrelationID != null ? this.jmsCorrelationID.getBytes() : null;
1140    }
1141
1142
1143    /**
1144     * Sets the correlation ID as an array of bytes for the message.
1145     * <p/>
1146     * <P>The array is copied before the method returns, so
1147     * future modifications to the array will not alter this message header.
1148     * <p/>
1149     * <P>If a provider supports the native concept of correlation ID, a
1150     * JMS client may need to assign specific <CODE>JMSCorrelationID</CODE>
1151     * values to match those expected by native messaging clients.
1152     * JMS providers without native correlation ID values are not required to
1153     * support this method and its corresponding get method; their
1154     * implementation may throw a
1155     * <CODE>java.lang.UnsupportedOperationException</CODE>.
1156     * <p/>
1157     * <P>The use of a <CODE>byte[]</CODE> value for
1158     * <CODE>JMSCorrelationID</CODE> is non-portable.
1159     *
1160     * @param correlationID the correlation ID value as an array of bytes
1161     * @see javax.jms.Message#setJMSCorrelationID(String)
1162     * @see javax.jms.Message#getJMSCorrelationID()
1163     * @see javax.jms.Message#getJMSCorrelationIDAsBytes()
1164     */
1165
1166    public void setJMSCorrelationIDAsBytes(byte[] correlationID) {
1167        if (correlationID == null) {
1168            this.jmsCorrelationID = null;
1169        }
1170        else {
1171            this.jmsCorrelationID = new String(correlationID);
1172        }
1173    }
1174
1175
1176    /**
1177     * Sets the correlation ID for the message.
1178     * <p/>
1179     * <P>A client can use the <CODE>JMSCorrelationID</CODE> header field to
1180     * link one message with another. A typical use is to link a response
1181     * message with its request message.
1182     * <p/>
1183     * <P><CODE>JMSCorrelationID</CODE> can hold one of the following:
1184     * <UL>
1185     * <LI>A provider-specific message ID
1186     * <LI>An application-specific <CODE>String</CODE>
1187     * <LI>A provider-native <CODE>byte[]</CODE> value
1188     * </UL>
1189     * <p/>
1190     * <P>Since each message sent by a JMS provider is assigned a message ID
1191     * value, it is convenient to link messages via message ID. All message ID
1192     * values must start with the <CODE>'ID:'</CODE> prefix.
1193     * <p/>
1194     * <P>In some cases, an application (made up of several clients) needs to
1195     * use an application-specific value for linking messages. For instance,
1196     * an application may use <CODE>JMSCorrelationID</CODE> to hold a value
1197     * referencing some external information. Application-specified values
1198     * must not start with the <CODE>'ID:'</CODE> prefix; this is reserved for
1199     * provider-generated message ID values.
1200     * <p/>
1201     * <P>If a provider supports the native concept of correlation ID, a JMS
1202     * client may need to assign specific <CODE>JMSCorrelationID</CODE> values
1203     * to match those expected by clients that do not use the JMS API. A
1204     * <CODE>byte[]</CODE> value is used for this
1205     * purpose. JMS providers without native correlation ID values are not
1206     * required to support <CODE>byte[]</CODE> values. The use of a
1207     * <CODE>byte[]</CODE> value for <CODE>JMSCorrelationID</CODE> is
1208     * non-portable.
1209     *
1210     * @param correlationID the message ID of a message being referred to
1211     * @see javax.jms.Message#getJMSCorrelationID()
1212     * @see javax.jms.Message#getJMSCorrelationIDAsBytes()
1213     * @see javax.jms.Message#setJMSCorrelationIDAsBytes(byte[])
1214     */
1215
1216    public void setJMSCorrelationID(String correlationID) {
1217        this.jmsCorrelationID = correlationID;
1218    }
1219
1220
1221    /**
1222     * Gets the correlation ID for the message.
1223     * <p/>
1224     * <P>This method is used to return correlation ID values that are
1225     * either provider-specific message IDs or application-specific
1226     * <CODE>String</CODE> values.
1227     *
1228     * @return the correlation ID of a message as a <CODE>String</CODE>
1229     * @see javax.jms.Message#setJMSCorrelationID(String)
1230     * @see javax.jms.Message#getJMSCorrelationIDAsBytes()
1231     * @see javax.jms.Message#setJMSCorrelationIDAsBytes(byte[])
1232     */
1233
1234    public String getJMSCorrelationID() {
1235        return this.jmsCorrelationID;
1236    }
1237
1238
1239    /**
1240     * Gets the <CODE>Destination</CODE> object to which a reply to this
1241     * message should be sent.
1242     *
1243     * @return <CODE>Destination</CODE> to which to send a response to this
1244     *         message
1245     * @see javax.jms.Message#setJMSReplyTo(Destination)
1246     */
1247
1248    public Destination getJMSReplyTo() {
1249        return this.jmsReplyTo;
1250
1251    }
1252
1253
1254    /**
1255     * Sets the <CODE>Destination</CODE> object to which a reply to this
1256     * message should be sent.
1257     * <p/>
1258     * <P>The <CODE>JMSReplyTo</CODE> header field contains the destination
1259     * where a reply
1260     * to the current message should be sent. If it is null, no reply is
1261     * expected. The destination may be either a <CODE>Queue</CODE> object or
1262     * a <CODE>Topic</CODE> object.
1263     * <p/>
1264     * <P>Messages sent with a null <CODE>JMSReplyTo</CODE> value may be a
1265     * notification of some event, or they may just be some data the sender
1266     * thinks is of interest.
1267     * <p/>
1268     * <P>Messages with a <CODE>JMSReplyTo</CODE> value typically expect a
1269     * response. A response is optional; it is up to the client to decide.
1270     * These messages are called requests. A message sent in response to a
1271     * request is called a reply.
1272     * <p/>
1273     * <P>In some cases a client may wish to match a request it sent earlier
1274     * with a reply it has just received. The client can use the
1275     * <CODE>JMSCorrelationID</CODE> header field for this purpose.
1276     *
1277     * @param replyTo <CODE>Destination</CODE> to which to send a response to
1278     *                this message
1279     * @see javax.jms.Message#getJMSReplyTo()
1280     */
1281
1282    public void setJMSReplyTo(Destination replyTo) {
1283        this.jmsReplyTo = (ActiveMQDestination) replyTo;
1284    }
1285
1286
1287    /**
1288     * Gets the <CODE>Destination</CODE> object for this message.
1289     * <p/>
1290     * <P>The <CODE>JMSDestination</CODE> header field contains the
1291     * destination to which the message is being sent.
1292     * <p/>
1293     * <P>When a message is sent, this field is ignored. After completion
1294     * of the <CODE>send</CODE> or <CODE>publish</CODE> method, the field
1295     * holds the destination specified by the method.
1296     * <p/>
1297     * <P>When a message is received, its <CODE>JMSDestination</CODE> value
1298     * must be equivalent to the value assigned when it was sent.
1299     *
1300     * @return the destination of this message
1301     * @see javax.jms.Message#setJMSDestination(Destination)
1302     */
1303
1304    public Destination getJMSDestination() {
1305        return this.jmsDestination;
1306    }
1307
1308
1309    /**
1310     * Sets the <CODE>Destination</CODE> object for this message.
1311     * <p/>
1312     * <P>JMS providers set this field when a message is sent. This method
1313     * can be used to change the value for a message that has been received.
1314     *
1315     * @param destination the destination for this message
1316     * @see javax.jms.Message#getJMSDestination()
1317     */
1318
1319    public void setJMSDestination(Destination destination) {
1320        this.jmsDestination = (ActiveMQDestination) destination;
1321    }
1322
1323
1324    /**
1325     * Gets the <CODE>DeliveryMode</CODE> value specified for this message.
1326     *
1327     * @return the delivery mode for this message
1328     * @see javax.jms.Message#setJMSDeliveryMode(int)
1329     * @see javax.jms.DeliveryMode
1330     */
1331
1332    public int getJMSDeliveryMode() {
1333        return this.jmsDeliveryMode;
1334    }
1335
1336
1337    /**
1338     * Sets the <CODE>DeliveryMode</CODE> value for this message.
1339     * <p/>
1340     * <P>JMS providers set this field when a message is sent. This method
1341     * can be used to change the value for a message that has been received.
1342     *
1343     * @param deliveryMode the delivery mode for this message
1344     * @see javax.jms.Message#getJMSDeliveryMode()
1345     * @see javax.jms.DeliveryMode
1346     */
1347
1348    public void setJMSDeliveryMode(int deliveryMode) {
1349        this.jmsDeliveryMode = deliveryMode;
1350    }
1351
1352
1353    /**
1354     * Gets an indication of whether this message is being redelivered.
1355     * <p/>
1356     * <P>If a client receives a message with the <CODE>JMSRedelivered</CODE>
1357     * field set,
1358     * it is likely, but not guaranteed, that this message was delivered
1359     * earlier but that its receipt was not acknowledged
1360     * at that time.
1361     *
1362     * @return true if this message is being redelivered
1363     * @see javax.jms.Message#setJMSRedelivered(boolean)
1364     */
1365
1366    public boolean getJMSRedelivered() {
1367        return this.jmsRedelivered;
1368    }
1369
1370
1371    /**
1372     * Specifies whether this message is being redelivered.
1373     * <p/>
1374     * <P>This field is set at the time the message is delivered. This
1375     * method can be used to change the value for a message that has
1376     * been received.
1377     *
1378     * @param redelivered an indication of whether this message is being
1379     *                    redelivered
1380     * @see javax.jms.Message#getJMSRedelivered()
1381     */
1382
1383    public void setJMSRedelivered(boolean redelivered) {
1384        this.jmsRedelivered = redelivered;
1385    }
1386
1387
1388    /**
1389     * Gets the message type identifier supplied by the client when the
1390     * message was sent.
1391     *
1392     * @return the message type
1393     * @see javax.jms.Message#setJMSType(String)
1394     */
1395
1396    public String getJMSType() {
1397        return this.jmsType;
1398    }
1399
1400    /**
1401     * Sets the message type.
1402     * <p/>
1403     * <P>Some JMS providers use a message repository that contains the
1404     * definitions of messages sent by applications. The <CODE>JMSType</CODE>
1405     * header field may reference a message's definition in the provider's
1406     * repository.
1407     * <p/>
1408     * <P>The JMS API does not define a standard message definition repository,
1409     * nor does it define a naming policy for the definitions it contains.
1410     * <p/>
1411     * <P>Some messaging systems require that a message type definition for
1412     * each application message be created and that each message specify its
1413     * type. In order to work with such JMS providers, JMS clients should
1414     * assign a value to <CODE>JMSType</CODE>, whether the application makes
1415     * use of it or not. This ensures that the field is properly set for those
1416     * providers that require it.
1417     * <p/>
1418     * <P>To ensure portability, JMS clients should use symbolic values for
1419     * <CODE>JMSType</CODE> that can be configured at installation time to the
1420     * values defined in the current provider's message repository. If string
1421     * literals are used, they may not be valid type names for some JMS
1422     * providers.
1423     *
1424