001 /**
002 *
003 * Copyright 2004 Protique Ltd
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 **/
018
019 package org.activemq.message;
020
021 import java.io.ByteArrayInputStream;
022 import java.io.ByteArrayOutputStream;
023 import java.io.DataInput;
024 import java.io.DataInputStream;
025 import java.io.DataOutput;
026 import java.io.DataOutputStream;
027 import java.io.IOException;
028 import java.util.Collections;
029 import java.util.Enumeration;
030 import java.util.HashMap;
031 import java.util.Iterator;
032 import java.util.Map;
033 import java.util.List;
034 import java.util.ArrayList;
035 import java.util.StringTokenizer;
036
037 import javax.jms.DeliveryMode;
038 import javax.jms.Destination;
039 import javax.jms.JMSException;
040 import javax.jms.Message;
041 import javax.jms.MessageFormatException;
042 import javax.jms.MessageNotWriteableException;
043
044 import org.activemq.io.util.ByteArray;
045 import org.activemq.io.util.ByteArrayCompression;
046 import org.activemq.io.util.MemoryManageable;
047 import org.activemq.service.MessageIdentity;
048 import org.activemq.util.IdGenerator;
049
050 /**
051 * The <CODE>Message</CODE> interface is the root interface of all JMS
052 * messages. It defines the message header and the <CODE>acknowledge</CODE>
053 * method used for all messages.
054 * <p/>
055 * <P>Most message-oriented middleware (MOM) products treat messages as
056 * lightweight entities that consist
057 * of a header and a payload. The header contains fields used for message
058 * routing and identification; the payload contains the application data
059 * being sent.
060 * <p/>
061 * <P>Within this general form, the definition of a message varies
062 * significantly across products. It would be quite difficult for the JMS API
063 * to support all of these message models.
064 * <p/>
065 * <P>With this in mind, the JMS message model has the following goals:
066 * <UL>
067 * <LI>Provide a single, unified message API
068 * <LI>Provide an API suitable for creating messages that match the
069 * format used by provider-native messaging applications
070 * <LI>Support the development of heterogeneous applications that span
071 * operating systems, machine architectures, and computer languages
072 * <LI>Support messages containing objects in the Java programming language
073 * ("Java objects")
074 * <LI>Support messages containing Extensible Markup Language (XML) pages
075 * </UL>
076 * <p/>
077 * <P>JMS messages are composed of the following parts:
078 * <UL>
079 * <LI>Header - All messages support the same set of header fields.
080 * Header fields contain values used by both clients and providers to
081 * identify and route messages.
082 * <LI>Properties - Each message contains a built-in facility for supporting
083 * application-defined property values. Properties provide an efficient
084 * mechanism for supporting application-defined message filtering.
085 * <LI>Body - The JMS API defines several types of message body, which cover
086 * the majority of messaging styles currently in use.
087 * </UL>
088 * <p/>
089 * <H4>Message Bodies</H4>
090 * <p/>
091 * <P>The JMS API defines five types of message body:
092 * <UL>
093 * <LI>Stream - A <CODE>StreamMessage</CODE> object's message body contains
094 * a stream of primitive values in the Java programming
095 * language ("Java primitives"). It is filled and read sequentially.
096 * <LI>Map - A <CODE>MapMessage</CODE> object's message body contains a set
097 * of name-value pairs, where names are <CODE>String</CODE>
098 * objects, and values are Java primitives. The entries can be accessed
099 * 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 BETWEEN 15 AND 19"</CODE> is
408 * equivalent to
409 * <CODE>"age >= 15 AND age <= 19"</CODE>
410 * <LI><CODE>"age NOT BETWEEN 15 AND 19"</CODE>
411 * is equivalent to
412 * <CODE>"age < 15 OR age > 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 IN (' UK', 'US', '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 = ' UK') OR (Country = ' US') OR (Country = ' France')"</CODE>
424 * <LI><CODE>"Country NOT IN (' UK', 'US', '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 ((Country = ' UK') OR (Country = ' US') OR (Country = ' 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 LIKE '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 LIKE 'l_se'"</CODE> is true for
448 * <CODE>'lose'</CODE> and false for <CODE>'loose'</CODE>
449 * <LI><CODE>"underscored LIKE '\_%' ESCAPE '\'"</CODE>
450 * is true for <CODE>'_foo'</CODE> and false for <CODE>'bar'</CODE>
451 * <LI><CODE>"phone NOT LIKE '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 IS 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 IS NOT 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 = 'car' AND color = 'blue' AND weight > 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 * @param type the message type
1425 * @see javax.jms.Message#getJMSType()
1426 */
1427
1428 public void setJMSType(String type) {
1429 this.jmsType = type;
1430 }
1431
1432
1433 /**
1434 * Gets the message's expiration value.
1435 * <p/>
1436 * <P>When a message is sent, the <CODE>JMSExpiration</CODE> header field
1437 * is left unassigned. After completion of the <CODE>send</CODE> or
1438 * <CODE>publish</CODE> method, it holds the expiration time of the
1439 * message. This is the sum of the time-to-live value specified by the
1440 * client and the GMT at the time of the <CODE>send</CODE> or
1441 * <CODE>publish</CODE>.
1442 * <p/>
1443 * <P>If the time-to-live is specified as zero, <CODE>JMSExpiration</CODE>
1444 * is set to zero to indicate that the message does not expire.
1445 * <p/>
1446 * <P>When a message's expiration time is reached, a provider should
1447 * discard it. The JMS API does not define any form of notification of
1448 * message expiration.
1449 * <p/>
1450 * <P>Clients should not receive messages that have expired; however,
1451 * the JMS API does not guarantee that this will not happen.
1452 *
1453 * @return the time the message expires, which is the sum of the
1454 * time-to-live value specified by the client and the GMT at the
1455 * time of the send
1456 * @see javax.jms.Message#setJMSExpiration(long)
1457 */
1458
1459 public long getJMSExpiration() {
1460 return this.jmsExpiration;
1461 }
1462
1463
1464 /**
1465 * Sets the message's expiration value.
1466 * <p/>
1467 * <P>JMS providers set this field when a message is sent. This method
1468 * can be used to change the value for a message that has been received.
1469 *
1470 * @param expiration the message's expiration time
1471 * @see javax.jms.Message#getJMSExpiration()
1472 */
1473
1474 public void setJMSExpiration(long expiration) {
1475 this.jmsExpiration = expiration;
1476 }
1477
1478 /**
1479 * Gets the message priority level.
1480 * <p/>
1481 * <P>The JMS API defines ten levels of priority value, with 0 as the
1482 * lowest
1483 * priority and 9 as the highest. In addition, clients should consider
1484 * priorities 0-4 as gradations of normal priority and priorities 5-9
1485 * as gradations of expedited priority.
1486 * <p/>
1487 * <P>The JMS API does not require that a provider strictly implement
1488 * priority
1489 * ordering of messages; however, it should do its best to deliver
1490 * expedited messages ahead of normal messages.
1491 *
1492 * @return the default message priority
1493 * @see javax.jms.Message#setJMSPriority(int)
1494 */
1495
1496 public int getJMSPriority() {
1497 return this.jmsPriority;
1498 }
1499
1500
1501 /**
1502 * Sets the priority level for this message.
1503 * <p/>
1504 * <P>JMS providers set this field when a message is sent. This method
1505 * can be used to change the value for a message that has been received.
1506 *
1507 * @param priority the priority of this message
1508 * @see javax.jms.Message#getJMSPriority()
1509 */
1510
1511 public void setJMSPriority(int priority) {
1512 this.jmsPriority = priority;
1513 }
1514
1515 /**
1516 * Clears a message's properties.
1517 * <p/>
1518 * <P>The message's header fields and body are not cleared.
1519 */
1520
1521 public synchronized void clearProperties() {
1522 if (this.properties != null) {
1523 this.properties.clear();
1524 }
1525 this.readOnlyProperties = false;
1526 }
1527
1528
1529 /**
1530 * Indicates whether a property value exists.
1531 *
1532 * @param name the name of the property to test
1533 * @return true if the property exists
1534 */
1535
1536 public boolean propertyExists(String name) {
1537 return this.properties != null ? this.properties.containsKey(name) : false;
1538 }
1539
1540
1541 /**
1542 * Returns the value of the <CODE>boolean</CODE> property with the
1543 * specified name.
1544 *
1545 * @param name the name of the <CODE>boolean</CODE> property
1546 * @return the <CODE>boolean</CODE> property value for the specified name
1547 * @throws JMSException if the JMS provider fails to get the property
1548 * value due to some internal error.
1549 * @throws MessageFormatException if this type conversion is invalid.
1550 */
1551
1552 public boolean getBooleanProperty(String name) throws JMSException {
1553 return vanillaToBoolean(this.properties, name);
1554 }
1555
1556
1557 /**
1558 * Returns the value of the <CODE>byte</CODE> property with the specified
1559 * name.
1560 *
1561 * @param name the name of the <CODE>byte</CODE> property
1562 * @return the <CODE>byte</CODE> property value for the specified name
1563 * @throws JMSException if the JMS provider fails to get the property
1564 * value due to some internal error.
1565 * @throws MessageFormatException if this type conversion is invalid.
1566 */
1567
1568 public byte getByteProperty(String name) throws JMSException {
1569 return vanillaToByte(this.properties, name);
1570 }
1571
1572
1573 /**
1574 * Returns the value of the <CODE>short</CODE> property with the specified
1575 * name.
1576 *
1577 * @param name the name of the <CODE>short</CODE> property
1578 * @return the <CODE>short</CODE> property value for the specified name
1579 * @throws JMSException if the JMS provider fails to get the property
1580 * value due to some internal error.
1581 * @throws MessageFormatException if this type conversion is invalid.
1582 */
1583
1584 public short getShortProperty(String name) throws JMSException {
1585 return vanillaToShort(this.properties, name);
1586 }
1587
1588
1589 /**
1590 * Returns the value of the <CODE>int</CODE> property with the specified
1591 * name.
1592 *
1593 * @param name the name of the <CODE>int</CODE> property
1594 * @return the <CODE>int</CODE> property value for the specified name
1595 * @throws JMSException if the JMS provider fails to get the property
1596 * value due to some internal error.
1597 * @throws MessageFormatException if this type conversion is invalid.
1598 */
1599
1600 public int getIntProperty(String name) throws JMSException {
1601 return vanillaToInt(this.properties, name);
1602 }
1603
1604
1605 /**
1606 * Returns the value of the <CODE>long</CODE> property with the specified
1607 * name.
1608 *
1609 * @param name the name of the <CODE>long</CODE> property
1610 * @return the <CODE>long</CODE> property value for the specified name
1611 * @throws JMSException if the JMS provider fails to get the property
1612 * value due to some internal error.
1613 * @throws MessageFormatException if this type conversion is invalid.
1614 */
1615
1616 public long getLongProperty(String name) throws JMSException {
1617 return vanillaToLong(this.properties, name);
1618 }
1619
1620
1621 /**
1622 * Returns the value of the <CODE>float</CODE> property with the specified
1623 * name.
1624 *
1625 * @param name the name of the <CODE>float</CODE> property
1626 * @return the <CODE>float</CODE> property value for the specified name
1627 * @throws JMSException if the JMS provider fails to get the property
1628 * value due to some internal error.
1629 * @throws MessageFormatException if this type conversion is invalid.
1630 */
1631
1632 public float getFloatProperty(String name) throws JMSException {
1633 return vanillaToFloat(this.properties, name);
1634 }
1635
1636
1637 /**
1638 * Returns the value of the <CODE>double</CODE> property with the specified
1639 * name.
1640 *
1641 * @param name the name of the <CODE>double</CODE> property
1642 * @return the <CODE>double</CODE> property value for the specified name
1643 * @throws JMSException if the JMS provider fails to get the property
1644 * value due to some internal error.
1645 * @throws MessageFormatException if this type conversion is invalid.
1646 */
1647
1648 public double getDoubleProperty(String name) throws JMSException {
1649 return vanillaToDouble(this.properties, name);
1650 }
1651
1652
1653 /**
1654 * Returns the value of the <CODE>String</CODE> property with the specified
1655 * name.
1656 *
1657 * @param name the name of the <CODE>String</CODE> property
1658 * @return the <CODE>String</CODE> property value for the specified name;
1659 * if there is no property by this name, a null value is returned
1660 * @throws JMSException if the JMS provider fails to get the property
1661 * value due to some internal error.
1662 * @throws MessageFormatException if this type conversion is invalid.
1663 */
1664
1665 public String getStringProperty(String name) throws JMSException {
1666 return vanillaToString(this.properties, name);
1667 }
1668
1669
1670 /**
1671 * Returns the value of the Java object property with the specified name.
1672 * <p/>
1673 * <P>This method can be used to return, in objectified format,
1674 * an object that has been stored as a property in the message with the
1675 * equivalent <CODE>setObjectProperty</CODE> method call, or its equivalent
1676 * primitive <CODE>set<I>type</I>Property</CODE> method.
1677 *
1678 * @param name the name of the Java object property
1679 * @return the Java object property value with the specified name, in
1680 * objectified format (for example, if the property was set as an
1681 * <CODE>int</CODE>, an <CODE>Integer</CODE> is
1682 * returned); if there is no property by this name, a null value
1683 * is returned
1684 */
1685
1686 public Object getObjectProperty(String name) {
1687 return this.properties != null ? this.properties.get(name) : null;
1688 }
1689
1690
1691 /**
1692 * Returns an <CODE>Enumeration</CODE> of all the property names.
1693 * <p/>
1694 * <P>Note that JMS standard header fields are not considered
1695 * properties and are not returned in this enumeration.
1696 *
1697 * @return an enumeration of all the names of property values
1698 *
1699 * @Transient
1700 */
1701 public Enumeration getPropertyNames() {
1702 if (this.properties == null) {
1703 this.properties = new HashMap();
1704 }
1705 return Collections.enumeration(this.properties.keySet());
1706 }
1707
1708 /**
1709 * Retrieve the message properties as a Map
1710 *
1711 * @return the Map representing the properties or null if not set or used
1712 */
1713
1714 public Map getProperties() {
1715 return this.properties;
1716 }
1717
1718 /**
1719 * Set the Message's properties from an external source
1720 * No checking on correct types is done by this method
1721 *
1722 * @param newProperties
1723 */
1724
1725 public void setProperties(Map newProperties) {
1726 this.properties = newProperties;
1727 }
1728
1729
1730 /**
1731 * Sets a <CODE>boolean</CODE> property value with the specified name into
1732 * the message.
1733 *
1734 * @param name the name of the <CODE>boolean</CODE> property
1735 * @param value the <CODE>boolean</CODE> property value to set
1736 * @throws JMSException if the JMS provider fails to set the property
1737 * due to some internal error.
1738 * @throws IllegalArgumentException if the name is null or if the name is
1739 * an empty string.
1740 * @throws MessageNotWriteableException if properties are read-only
1741 */
1742
1743 public void setBooleanProperty(String name, boolean value) throws JMSException {
1744 prepareProperty(name);
1745 this.properties.put(name, (value) ? Boolean.TRUE : Boolean.FALSE);
1746 }
1747
1748
1749 /**
1750 * Sets a <CODE>byte</CODE> property value with the specified name into
1751 * the message.
1752 *
1753 * @param name the name of the <CODE>byte</CODE> property
1754 * @param value the <CODE>byte</CODE> property value to set
1755 * @throws JMSException if the JMS provider fails to set the property
1756 * due to some internal error.
1757 * @throws IllegalArgumentException if the name is null or if the name is
1758 * an empty string.
1759 * @throws MessageNotWriteableException if properties are read-only
1760 */
1761
1762 public void setByteProperty(String name, byte value) throws JMSException {
1763 prepareProperty(name);
1764 this.properties.put(name, new Byte(value));
1765 }
1766
1767
1768 /**
1769 * Sets a <CODE>short</CODE> property value with the specified name into
1770 * the message.
1771 *
1772 * @param name the name of the <CODE>short</CODE> property
1773 * @param value the <CODE>short</CODE> property value to set
1774 * @throws JMSException if the JMS provider fails to set the property
1775 * due to some internal error.
1776 * @throws IllegalArgumentException if the name is null or if the name is
1777 * an empty string.
1778 * @throws MessageNotWriteableException if properties are read-only
1779 */
1780
1781 public void setShortProperty(String name, short value) throws JMSException {
1782 prepareProperty(name);
1783 this.properties.put(name, new Short(value));
1784 }
1785
1786
1787 /**
1788 * Sets an <CODE>int</CODE> property value with the specified name into
1789 * the message.
1790 *
1791 * @param name the name of the <CODE>int</CODE> property
1792 * @param value the <CODE>int</CODE> property value to set
1793 * @throws JMSException if the JMS provider fails to set the property
1794 * due to some internal error.
1795 * @throws IllegalArgumentException if the name is null or if the name is
1796 * an empty string.
1797 * @throws MessageNotWriteableException if properties are read-only
1798 */
1799
1800 public void setIntProperty(String name, int value) throws JMSException {
1801 prepareProperty(name);
1802 this.properties.put(name, new Integer(value));
1803 }
1804
1805
1806 /**
1807 * Sets a <CODE>long</CODE> property value with the specified name into
1808 * the message.
1809 *
1810 * @param name the name of the <CODE>long</CODE> property
1811 * @param value the <CODE>long</CODE> property value to set
1812 * @throws JMSException if the JMS provider fails to set the property
1813 * due to some internal error.
1814 * @throws IllegalArgumentException if the name is null or if the name is
1815 * an empty string.
1816 * @throws MessageNotWriteableException if properties are read-only
1817 */
1818
1819 public void setLongProperty(String name, long value) throws JMSException {
1820 prepareProperty(name);
1821 this.properties.put(name, new Long(value));
1822 }
1823
1824
1825 /**
1826 * Sets a <CODE>float</CODE> property value with the specified name into
1827 * the message.
1828 *
1829 * @param name the name of the <CODE>float</CODE> property
1830 * @param value the <CODE>float</CODE> property value to set
1831 * @throws JMSException if the JMS provider fails to set the property
1832 * due to some internal error.
1833 * @throws IllegalArgumentException if the name is null or if the name is
1834 * an empty string.
1835 * @throws MessageNotWriteableException if properties are read-only
1836 */
1837
1838 public void setFloatProperty(String name, float value) throws JMSException {
1839 prepareProperty(name);
1840 this.properties.put(name, new Float(value));
1841
1842 }
1843
1844
1845 /**
1846 * Sets a <CODE>double</CODE> property value with the specified name into
1847 * the message.
1848 *
1849 * @param name the name of the <CODE>double</CODE> property
1850 * @param value the <CODE>double</CODE> property value to set
1851 * @throws JMSException if the JMS provider fails to set the property
1852 * due to some internal error.
1853 * @throws IllegalArgumentException if the name is null or if the name is
1854 * an empty string.
1855 * @throws MessageNotWriteableException if properties are read-only
1856 */
1857
1858 public void setDoubleProperty(String name, double value) throws JMSException {
1859 prepareProperty(name);
1860 this.properties.put(name, new Double(value));
1861 }
1862
1863
1864 /**
1865 * Sets a <CODE>String</CODE> property value with the specified name into
1866 * the message.
1867 *
1868 * @param name the name of the <CODE>String</CODE> property
1869 * @param value the <CODE>String</CODE> property value to set
1870 * @throws JMSException if the JMS provider fails to set the property
1871 * due to some internal error.
1872 * @throws IllegalArgumentException if the name is null or if the name is
1873 * an empty string.
1874 * @throws MessageNotWriteableException if properties are read-only
1875 */
1876
1877 public void setStringProperty(String name, String value) throws JMSException {
1878 prepareProperty(name);
1879 if (value == null) {
1880 this.properties.remove(name);
1881 }
1882 else {
1883 this.properties.put(name, value);
1884 }
1885 }
1886
1887
1888 /**
1889 * Sets a Java object property value with the specified name into the
1890 * message.
1891 * <p/>
1892 * <P>Note that this method works only for the objectified primitive
1893 * object types (<CODE>Integer</CODE>, <CODE>Double</CODE>,
1894 * <CODE>Long</CODE> ...) and <CODE>String</CODE> objects.
1895 *
1896 * @param name the name of the Java object property
1897 * @param value the Java object property value to set
1898 * @throws JMSException if the JMS provider fails to set the property
1899 * due to some internal error.
1900 * @throws IllegalArgumentException if the name is null or if the name is
1901 * an empty string.
1902 * @throws MessageFormatException if the object is invalid
1903 * @throws MessageNotWriteableException if properties are read-only
1904 */
1905
1906 public void setObjectProperty(String name, Object value) throws JMSException {
1907 prepareProperty(name);
1908 if (value == null) {
1909 this.properties.remove(name);
1910 }
1911 else {
1912 if (value instanceof Number ||
1913 value instanceof Character ||
1914 value instanceof Boolean ||
1915 value instanceof String) {
1916 this.properties.put(name, value);
1917 }
1918 else {
1919 throw new MessageFormatException("Cannot set property to type: " + value.getClass().getName());
1920 }
1921 }
1922 }
1923
1924
1925 /**
1926 * Acknowledges all consumed messages of the session of this consumed
1927 * message.
1928 * <p/>
1929 * <P>All consumed JMS messages support the <CODE>acknowledge</CODE>
1930 * method for use when a client has specified that its JMS session's
1931 * consumed messages are to be explicitly acknowledged. By invoking
1932 * <CODE>acknowledge</CODE> on a consumed message, a client acknowledges
1933 * all messages consumed by the session that the message was delivered to.
1934 * <p/>
1935 * <P>Calls to <CODE>acknowledge</CODE> are ignored for both transacted
1936 * sessions and sessions specified to use implicit acknowledgement modes.
1937 * <p/>
1938 * <P>A client may individually acknowledge each message as it is consumed,
1939 * or it may choose to acknowledge messages as an application-defined group
1940 * (which is done by calling acknowledge on the last received message of the group,
1941 * thereby acknowledging all messages consumed by the session.)
1942 * <p/>
1943 * <P>Messages that have been received but not acknowledged may be
1944 * redelivered.
1945 *
1946 * @throws JMSException if the JMS provider fails to acknowledge the
1947 * messages due to some internal error.
1948 * @throws javax.jms.IllegalStateException
1949 * if this method is called on a closed
1950 * session.
1951 * @see javax.jms.Session#CLIENT_ACKNOWLEDGE
1952 */
1953
1954 public void acknowledge() throws JMSException {
1955 if (this.messageAcknowledge != null) {
1956 this.messageAcknowledge.acknowledge(this);
1957 }
1958 }
1959
1960
1961 /**
1962 * Clears out the message body. Clearing a message's body does not clear
1963 * its header values or property entries.
1964 * <p/>
1965 * <P>If this message body was read-only, calling this method leaves
1966 * the message body in the same state as an empty body in a newly
1967 * created message.
1968 *
1969 * @throws JMSException if the JMS provider fails to clear the message
1970 * body due to some internal error.
1971 */
1972
1973 public void clearBody() throws JMSException {
1974 this.readOnlyMessage = false;
1975 this.bodyAsBytes = null;
1976 }
1977
1978 boolean vanillaToBoolean(Map table, String name) throws JMSException {
1979 boolean result = false;
1980 Object value = getVanillaProperty(table, name);
1981 if (value != null) {
1982 if (value instanceof Boolean) {
1983 result = ((Boolean) value).booleanValue();
1984 }
1985 else if (value instanceof String) {
1986 // will throw a runtime exception if cannot convert
1987 result = Boolean.valueOf((String) value).booleanValue();
1988 }
1989 else {
1990 throw new MessageFormatException(name + " not a Boolean type");
1991 }
1992 }
1993 return result;
1994 }
1995
1996 byte vanillaToByte(Map table, String name) throws JMSException {
1997 byte result = 0;
1998 Object value = getVanillaProperty(table, name);
1999 if (value != null) {
2000 if (value instanceof Byte) {
2001 result = ((Byte) value).byteValue();
2002 }
2003 else if (value instanceof String) {
2004 result = Byte.valueOf((String) value).byteValue();
2005 }
2006 else {
2007 throw new MessageFormatException(name + " not a Byte type");
2008 }
2009 }
2010 else {
2011 //object doesn't exist - so treat as a null ..
2012 throw new NumberFormatException("Cannot interpret null as a Byte");
2013 }
2014 return result;
2015 }
2016
2017 short vanillaToShort(Map table, String name) throws JMSException {
2018 short result = 0;
2019 Object value = getVanillaProperty(table, name);
2020 if (value != null) {
2021 if (value instanceof Short) {
2022 result = ((Short) value).shortValue();
2023 }
2024 else if (value instanceof String) {
2025 return Short.valueOf((String) value).shortValue();
2026 }
2027 else if (value instanceof Byte) {
2028 result = ((Byte) value).byteValue();
2029 }
2030 else {
2031 throw new MessageFormatException(name + " not a Short type");
2032 }
2033 }
2034 else {
2035 throw new NumberFormatException(name + " is null");
2036 }
2037 return result;
2038 }
2039
2040 int vanillaToInt(Map table, String name) throws JMSException {
2041 int result = 0;
2042 Object value = getVanillaProperty(table, name);
2043 if (value != null) {
2044 if (value instanceof Integer) {
2045 result = ((Integer) value).intValue();
2046 }
2047 else if (value instanceof String) {
2048 result = Integer.valueOf((String) value).intValue();
2049 }
2050 else if (value instanceof Byte) {
2051 result = ((Byte) value).intValue();
2052 }
2053 else if (value instanceof Short) {
2054 result = ((Short) value).intValue();
2055 }
2056 else {
2057 throw new MessageFormatException(name + " not an Integer type");
2058 }
2059 }
2060 else {
2061 throw new NumberFormatException(name + " is null");
2062 }
2063 return result;
2064 }
2065
2066 long vanillaToLong(Map table, String name) throws JMSException {
2067 long result = 0;
2068 Object value = getVanillaProperty(table, name);
2069 if (value != null) {
2070 if (value instanceof Long) {
2071 result = ((Long) value).longValue();
2072 }
2073 else if (value instanceof String) {
2074 // will throw a runtime exception if cannot convert
2075 result = Long.valueOf((String) value).longValue();
2076 }
2077 else if (value instanceof Byte) {
2078 result = ((Byte) value).byteValue();
2079 }
2080 else if (value instanceof Short) {
2081 result = ((Short) value).shortValue();
2082 }
2083 else if (value instanceof Integer) {
2084 result = ((Integer) value).intValue();
2085 }
2086 else {
2087 throw new MessageFormatException(name + " not a Long type");
2088 }
2089 }
2090 else {
2091 throw new NumberFormatException(name + " is null");
2092 }
2093 return result;
2094 }
2095
2096 float vanillaToFloat(Map table, String name) throws JMSException {
2097 float result = 0.0f;
2098 Object value = getVanillaProperty(table, name);
2099 if (value != null) {
2100 if (value instanceof Float) {
2101 result = ((Float) value).floatValue();
2102 }
2103 else if (value instanceof String) {
2104 result = Float.valueOf((String) value).floatValue();
2105 }
2106 else {
2107 throw new MessageFormatException(name + " not a Float type: " + value.getClass());
2108 }
2109 }
2110 else {
2111 throw new NullPointerException(name + " is null");
2112 }
2113 return result;
2114 }
2115
2116 double vanillaToDouble(Map table, String name) throws JMSException {
2117 double result = 0.0d;
2118 Object value = getVanillaProperty(table, name);
2119 if (value != null) {
2120 if (value instanceof Double) {
2121 result = ((Double) value).doubleValue();
2122 }
2123 else if (value instanceof String) {
2124 result = Double.valueOf((String) value).doubleValue();
2125 }
2126 else if (value instanceof Float) {
2127 result = ((Float) value).floatValue();
2128 }
2129 else {
2130 throw new MessageFormatException(name + " not a Double type");
2131 }
2132 }
2133 else {
2134 throw new NullPointerException(name + " is null");
2135 }
2136 return result;
2137 }
2138
2139 Object getVanillaProperty(Map table, String name) {
2140 Object result = null;
2141 if (name == null) {
2142 throw new NullPointerException("name supplied is null");
2143 }
2144 result = getReservedProperty(name);
2145 if (result == null && table != null) {
2146 result = table.get(name);
2147 }
2148 return result;
2149 }
2150
2151 Object getReservedProperty(String name){
2152 Object result = null;
2153 if (name != null && name.equals(DELIVERY_COUNT_NAME)){
2154 result = new Integer(deliveryCount);
2155 }
2156 return result;
2157 }
2158
2159
2160 String vanillaToString(Map table, String name) throws JMSException {
2161 String result = null;
2162 if (table != null) {
2163 Object value = table.get(name);
2164 if (value != null) {
2165 if (value instanceof String || value instanceof Number || value instanceof Boolean) {
2166 result = value.toString();
2167 }
2168 else {
2169 throw new MessageFormatException(name + " not a String type");
2170 }
2171 }
2172 }
2173 return result;
2174 }
2175
2176 private void prepareProperty(String name) throws JMSException {
2177 if (name == null) {
2178 throw new IllegalArgumentException("Invalid property name: cannot be null");
2179 }
2180 if (name.length() == 0) {
2181 throw new IllegalArgumentException("Invalid property name: cannot be empty");
2182 }
2183 if (this.readOnlyProperties) {
2184 throw new MessageNotWriteableException("Properties are read-only");
2185 }
2186 if (this.properties == null) {
2187 this.properties = new HashMap();
2188 }
2189 }
2190
2191 /**
2192 * @return Returns the entryBrokerName.
2193 */
2194 public String getEntryBrokerName() {
2195 return this.entryBrokerName;
2196 }
2197
2198 /**
2199 * @param newEntryBrokerName The entryBrokerName to set.
2200 */
2201 public void setEntryBrokerName(String newEntryBrokerName) {
2202 this.entryBrokerName = newEntryBrokerName;
2203 }
2204
2205 /**
2206 * @return Returns the entryClusterName.
2207 */
2208 public String getEntryClusterName() {
2209 return this.entryClusterName;
2210 }
2211
2212 /**
2213 * @param newEntryClusterName The entryClusterName to set.
2214 */
2215 public void setEntryClusterName(String newEntryClusterName) {
2216 this.entryClusterName = newEntryClusterName;
2217 }
2218
2219 /**
2220 * @return Returns the consumerNos.
2221 *
2222 * @Transient
2223 */
2224 public int[] getConsumerNos() {
2225 return this.consumerNos;
2226 }
2227
2228 /**
2229 * @param newConsumerNos The consumerIDs to set.
2230 */
2231 public void setConsumerNos(int[] newConsumerNos) {
2232 this.consumerNos = newConsumerNos;
2233 }
2234
2235 /**
2236 * @return Returns the jmsClientID.
2237 */
2238 public String getJMSClientID() {
2239 return this.jmsClientID;
2240 }
2241
2242 /**
2243 * @param newJmsClientID The jmsClientID to set.
2244 */
2245 public void setJMSClientID(String newJmsClientID) {
2246 this.jmsClientID = newJmsClientID;
2247 }
2248
2249
2250
2251 /**
2252 * @return Returns true if this message is part of a transaction
2253 */
2254
2255 public boolean isPartOfTransaction() {
2256 return this.transactionId != null;
2257 }
2258
2259 /**
2260 * @return Returns the transactionId.
2261 *
2262 * @Transient
2263 */
2264 public Object getTransactionId() {
2265 return this.transactionId;
2266 }
2267
2268 /**
2269 * @param newTransactionId The transactionId to set.
2270 */
2271 public void setTransactionId(Object newTransactionId) {
2272 this.transactionId = newTransactionId;
2273 this.xaTransacted = newTransactionId!=null && newTransactionId.getClass()==ActiveMQXid.class;
2274 }
2275
2276 /**
2277 * @Transient
2278 * @return Returns the consumerId.
2279 */
2280 public String getConsumerIdentifer() {
2281 return consumerIdentifier;
2282 }
2283
2284 /**
2285 * @param consId The consumerId to set.
2286 */
2287 public void setConsumerIdentifer(String consId) {
2288 this.consumerIdentifier = consId;
2289 }
2290
2291 /**
2292 * @Transient
2293 * @return Returns the messageConsumed.
2294 */
2295 public boolean isMessageConsumed() {
2296 return messageConsumed;
2297 }
2298
2299 /**
2300 * @param messageConsumed The messageConsumed to set.
2301 */
2302 public void setMessageConsumed(boolean messageConsumed) {
2303 this.messageConsumed = messageConsumed;
2304 }
2305
2306
2307 /**
2308 * Prepare a message body for delivery
2309 *
2310 * @throws JMSException
2311 */
2312 public void prepareMessageBody() throws JMSException {
2313 }
2314
2315 /**
2316 * Convert the message body to data
2317 *
2318 * @throws IOException
2319 */
2320 public final void convertBodyToBytes() throws IOException {
2321 if (bodyAsBytes == null) {
2322 ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
2323 DataOutputStream dataOut = new DataOutputStream(bytesOut);
2324 writeBody(dataOut);
2325 dataOut.flush();
2326 bodyAsBytes = new ByteArray(bytesOut.toByteArray());
2327 dataOut.close();
2328 }
2329 }
2330
2331 /**
2332 * Builds the message body from data
2333 *
2334 * @throws IOException
2335 */
2336 public final void buildBodyFromBytes() throws IOException {
2337 if (bodyAsBytes != null) {
2338 //inflate bodyAsBytes if needed
2339 if (ByteArrayCompression.isCompressed(bodyAsBytes)){
2340 ByteArrayCompression compression = new ByteArrayCompression();
2341 bodyAsBytes = compression.inflate(bodyAsBytes);
2342 }
2343 ByteArrayInputStream bytesIn = new ByteArrayInputStream(bodyAsBytes.getBuf(),bodyAsBytes.getOffset(),bodyAsBytes.getLength());
2344 DataInputStream dataIn = new DataInputStream(bytesIn);
2345 readBody(dataIn);
2346 dataIn.close();
2347 }
2348 }
2349
2350 /**
2351 * Used serialize the message body to an output stream
2352 *
2353 * @param dataOut
2354 * @throws IOException
2355 */
2356
2357 public void writeBody(DataOutput dataOut) throws IOException {
2358
2359 }
2360
2361 /**
2362 * Used to help build the body from an input stream
2363 *
2364 * @param dataIn
2365 * @throws IOException
2366 */
2367
2368 public void readBody(DataInput dataIn) throws IOException {
2369
2370 }
2371
2372 /**
2373 * @return Returns the bodyAsBytes.
2374 * @throws IOException
2375 *
2376 * @Transient
2377 */
2378 public ByteArray getBodyAsBytes() throws IOException {
2379 if (bodyAsBytes == null) {
2380 convertBodyToBytes();
2381 }
2382 return bodyAsBytes;
2383 }
2384
2385 /**
2386 * return the data after applying compression
2387 * @param compression
2388 * @return compressed ByteArray
2389 * @throws IOException
2390 */
2391 public ByteArray getBodyAsBytes(ByteArrayCompression compression) throws IOException {
2392 bodyAsBytes = compression.deflate(getBodyAsBytes());
2393 return bodyAsBytes;
2394 }
2395
2396 /**
2397 * @return true if the body is already stored as bytes
2398 */
2399 public boolean isBodyConvertedToBytes(){
2400 return bodyAsBytes != null;
2401 }
2402
2403
2404 /**
2405 * @param data The bodyAsBytes to set.
2406 * @param offset
2407 * @param length
2408 */
2409 public void setBodyAsBytes(byte[] data,int offset, int length) {
2410 this.bodyAsBytes = new ByteArray(data);
2411 }
2412
2413 /**
2414 * set the body as bytes
2415 * @param ba
2416 */
2417 public void setBodyAsBytes(ByteArray ba){
2418 this.bodyAsBytes = ba;
2419 }
2420
2421 /**
2422 * write map properties to an output stream
2423 *
2424 * @param table
2425 * @param dataOut
2426 * @throws IOException
2427 */
2428
2429 public void writeMapProperties(Map table, DataOutput dataOut) throws IOException {
2430 if (table != null) {
2431 dataOut.writeShort(table.size());
2432 for (Iterator iter = table.keySet().iterator(); iter.hasNext();) {
2433 String key = iter.next().toString();
2434 dataOut.writeUTF(key);
2435 Object value = table.get(key);
2436
2437 if (value == null) {
2438 dataOut.write(ActiveMQMessage.NULL);
2439 }
2440 else if (value instanceof byte[]) {
2441 byte[] data = (byte[]) value;
2442 dataOut.write(ActiveMQMessage.BYTES);
2443 if (data != null) {
2444 dataOut.writeInt(data.length);
2445 dataOut.write(data);
2446 }
2447 else {
2448 dataOut.writeInt(-1);
2449 }
2450 }
2451 else if (value instanceof Byte) {
2452 dataOut.write(ActiveMQMessage.BYTE);
2453 Byte v = (Byte) value;
2454 dataOut.writeByte(v.byteValue());
2455 }
2456 else if (value instanceof Boolean) {
2457 dataOut.write(ActiveMQMessage.BOOLEAN);
2458 Boolean v = (Boolean) value;
2459 dataOut.writeBoolean(v.booleanValue());
2460 }
2461 else if (value instanceof String) {
2462 dataOut.write(ActiveMQMessage.STRING);
2463 dataOut.writeUTF(value.toString());
2464 }
2465 else if (value instanceof Character) {
2466 dataOut.write(ActiveMQMessage.CHAR);
2467 Character v = (Character) value;
2468 dataOut.writeChar(v.charValue());
2469 }
2470 else if (value instanceof Number) {
2471 Number v = (Number) value;
2472
2473 if (value instanceof Long) {
2474 dataOut.write(ActiveMQMessage.LONG);
2475 dataOut.writeLong(v.longValue());
2476 }
2477 else if (value instanceof Integer) {
2478 dataOut.write(ActiveMQMessage.INT);
2479 dataOut.writeInt(v.intValue());
2480 }
2481 else if (value instanceof Short) {
2482 dataOut.write(ActiveMQMessage.SHORT);
2483 dataOut.writeShort(v.shortValue());
2484 }
2485 else if (value instanceof Float) {
2486 dataOut.write(ActiveMQMessage.FLOAT);
2487 dataOut.writeFloat(v.floatValue());
2488 }
2489 else if (value instanceof Double) {
2490 dataOut.write(ActiveMQMessage.DOUBLE);
2491 dataOut.writeDouble(v.doubleValue());
2492 }
2493 }
2494 else {
2495 throw new RuntimeException("Do not know how to parse value of type: " + value.getClass());
2496 }
2497
2498 }
2499 }
2500 else {
2501 dataOut.writeShort(-1);
2502 }
2503 }
2504
2505 /**
2506 * @param dataIn
2507 * @return
2508 * @throws IOException
2509 */
2510 public Map readMapProperties(DataInput dataIn) throws IOException {
2511 Map result = null;
2512 int size = dataIn.readShort();
2513 if (size > -1) {
2514 result = new HashMap();
2515 for (int i = 0; i < size; i++) {
2516 String key = dataIn.readUTF();
2517 Object value = null;
2518 int type = dataIn.readByte();
2519
2520 if (type == ActiveMQMessage.NULL) {
2521 value = null;
2522 }
2523 else if (type == ActiveMQMessage.BYTES) {
2524 byte[] data = null;
2525 int dataSize = dataIn.readInt();
2526 if (dataSize > -1) {
2527 data = new byte[dataSize];
2528 dataIn.readFully(data);
2529 }
2530 value = data;
2531 }
2532 else if (type == ActiveMQMessage.BYTE) {
2533 value = new Byte(dataIn.readByte());
2534 }
2535 else if (type == ActiveMQMessage.BOOLEAN) {
2536 value = (dataIn.readBoolean()) ? Boolean.TRUE : Boolean.FALSE;
2537 }
2538 else if (type == ActiveMQMessage.STRING) {
2539 value = dataIn.readUTF();
2540 }
2541 else if (type == ActiveMQMessage.CHAR) {
2542 value = new Character(dataIn.readChar());
2543 }
2544 else if (type == ActiveMQMessage.LONG) {
2545 value = new Long(dataIn.readLong());
2546 }
2547 else if (type == ActiveMQMessage.INT) {
2548 value = new Integer(dataIn.readInt());
2549 }
2550 else if (type == ActiveMQMessage.SHORT) {
2551 value = new Short(dataIn.readShort());
2552 }
2553 else if (type == ActiveMQMessage.FLOAT) {
2554 value = new Float(dataIn.readFloat());
2555 }
2556 else if (type == ActiveMQMessage.DOUBLE) {
2557 value = new Double(dataIn.readDouble());
2558 }
2559 else {
2560 throw new RuntimeException("Do not know how to parse type: " + type);
2561 }
2562 result.put(key, value);
2563 }
2564 }
2565 return result;
2566 }
2567
2568 /**
2569 * @return Returns the xaTransacted.
2570 */
2571 public boolean isXaTransacted() {
2572 return xaTransacted;
2573 }
2574
2575 /**
2576 * @return the ActiveMQDestination
2577 *
2578 * @Transient
2579 */
2580 public ActiveMQDestination getJMSActiveMQDestination() {
2581 return jmsDestination;
2582 }
2583
2584 /**
2585 * @return the message identity, which contains the String messageID
2586 * and the lazily populated sequence number
2587 *
2588 * @Transient
2589 */
2590 public MessageIdentity getJMSMessageIdentity() {
2591 if (jmsMessageIdentity == null) {
2592 jmsMessageIdentity = new MessageIdentity(this.getJMSMessageID());
2593 }
2594 return jmsMessageIdentity;
2595 }
2596
2597 /**
2598 * @param messageIdentity - message identity for this object
2599 */
2600 public void setJMSMessageIdentity(MessageIdentity messageIdentity) {
2601 this.jmsMessageIdentity = messageIdentity;
2602 }
2603
2604 /**
2605 * Determine if the message originated in the network from the named broker
2606 * @param brokerName
2607 * @return true if entry point matches the brokerName
2608 */
2609 public boolean isEntryBroker(String brokerName){
2610 boolean result = entryBrokerName != null && brokerName != null && entryBrokerName.equals(brokerName);
2611 return result;
2612 }
2613
2614 /**
2615 * Determine if the message originated in the network from the named cluster
2616 * @param clusterName
2617 * @return true if the entry point matches the clusterName
2618 */
2619 public boolean isEntryCluster(String clusterName){
2620 boolean result = entryClusterName != null && clusterName != null && entryClusterName.equals(clusterName);
2621 return result;
2622 }
2623
2624 /**
2625 * @Transient
2626 * @return Returns the transientConsumed.
2627 */
2628 public boolean isTransientConsumed() {
2629 return transientConsumed;
2630 }
2631 /**
2632 * @param transientConsumed The transientConsumed to set.
2633 */
2634 public void setTransientConsumed(boolean transientConsumed) {
2635 this.transientConsumed = transientConsumed;
2636 }
2637
2638 /**
2639 * @return Returns the sequenceNumber.
2640 */
2641 public long getSequenceNumber() {
2642 return sequenceNumber;
2643 }
2644 /**
2645 * @param sequenceNumber The sequenceNumber to set.
2646 */
2647 public void setSequenceNumber(long sequenceNumber) {
2648 this.sequenceNumber = sequenceNumber;
2649 }
2650 /**
2651 * @return Returns the deliveryCount.
2652 */
2653 public int getDeliveryCount() {
2654 return deliveryCount;
2655 }
2656 /**
2657 * @param deliveryCount The deliveredCount to set.
2658 */
2659 public void setDeliveryCount(int deliveryCount) {
2660 this.deliveryCount = deliveryCount;
2661 }
2662
2663 /**
2664 * Increment the delivery count
2665 * @return the new value of the delivery count
2666 */
2667 public int incrementDeliveryCount(){
2668 return ++this.deliveryCount;
2669 }
2670
2671 /**
2672 * @return true if the delivery mode is persistent
2673 */
2674 public boolean isPersistent(){
2675 return jmsDeliveryMode == DeliveryMode.PERSISTENT;
2676 }
2677
2678 /**
2679 * @return Returns the dispatchedFromDLQ.
2680 */
2681 public boolean isDispatchedFromDLQ() {
2682 return dispatchedFromDLQ;
2683 }
2684 /**
2685 * @param dispatchedFromDLQ The dispatchedFromDLQ to set.
2686 */
2687 public void setDispatchedFromDLQ(boolean dispatchedFromDLQ) {
2688 this.dispatchedFromDLQ = dispatchedFromDLQ;
2689 }
2690
2691 /**
2692 * @return Returns the messsageHandle.
2693 */
2694 public short getMesssageHandle() {
2695 return messsageHandle;
2696 }
2697 /**
2698 * @param messsageHandle The messsageHandle to set.
2699 */
2700 public void setMesssageHandle(short messsageHandle) {
2701 this.messsageHandle = messsageHandle;
2702 }
2703 /**
2704 * @return Returns the externalMessageId.
2705 */
2706 public boolean isExternalMessageId() {
2707 return externalMessageId;
2708 }
2709 /**
2710 * @param externalMessageId The externalMessageId to set.
2711 */
2712 public void setExternalMessageId(boolean externalMessageId) {
2713 this.externalMessageId = externalMessageId;
2714 }
2715 /**
2716 * @return Returns the producerKey.
2717 */
2718 public String getProducerKey() {
2719 return producerKey;
2720 }
2721 /**
2722 * @param producerKey The producerKey to set.
2723 */
2724 public void setProducerKey(String producerKey) {
2725 this.producerKey = producerKey;
2726 }
2727
2728 /**
2729 * reset message fragmentation infomation
2730 * on this message
2731 *
2732 */
2733 public void resetMessagePart(){
2734 messagePart = false;
2735 partNumber = 0;
2736 parentMessageID = null;
2737 }
2738 /**
2739 * @return Returns the messagePart.
2740 */
2741 public boolean isMessagePart() {
2742 return messagePart;
2743 }
2744
2745 /**
2746 * @return true if this is the last part of a fragmented message
2747 */
2748 public boolean isLastMessagePart(){
2749 return numberOfParts -1 == partNumber;
2750 }
2751 /**
2752 * @param messagePart The messagePart to set.
2753 */
2754 public void setMessagePart(boolean messagePart) {
2755 this.messagePart = messagePart;
2756 }
2757 /**
2758 * @return Returns the numberOfParts.
2759 */
2760 public short getNumberOfParts() {
2761 return numberOfParts;
2762 }
2763 /**
2764 * @param numberOfParts The numberOfParts to set.
2765 */
2766 public void setNumberOfParts(short numberOfParts) {
2767 this.numberOfParts = numberOfParts;
2768 }
2769 /**
2770 * @return Returns the partNumber.
2771 */
2772 public short getPartNumber() {
2773 return partNumber;
2774 }
2775 /**
2776 * @param partNumber The partNumber to set.
2777 */
2778 public void setPartNumber(short partNumber) {
2779 this.partNumber = partNumber;
2780 }
2781 /**
2782 * @return Returns the parentMessageId.
2783 */
2784 public String getParentMessageID() {
2785 return parentMessageID;
2786 }
2787 /**
2788 * @param parentMessageId The parentMessageId to set.
2789 */
2790 public void setParentMessageID(String parentMessageId) {
2791 this.parentMessageID = parentMessageId;
2792 }
2793
2794 public int getPriority() {
2795 return getJMSPriority();
2796 }
2797
2798
2799 /**
2800 * A helper method for the OpenWire protocol
2801 */
2802 public String getTransactionIDString() throws IOException {
2803 return ActiveMQXid.transactionIDToString(getTransactionId());
2804 }
2805
2806 /**
2807 * A helper method for the OpenWire protocol
2808 */
2809 public void setTransactionIDString(String text) throws IOException {
2810 setTransactionId(ActiveMQXid.transactionIDFromString(text));
2811 }
2812
2813 }