All JMS requirements as per 1.0.2b of the specification
3-2
3-3
3-7
http://java.sun.com/products/jms/javadoc-102a/javax/jms/BytesMessage.html http://java.sun.com/products/jms/javadoc-102a/javax/jms/StreamMessage.html A null message selector indicates that there is no message selector for the message consumer. section.3.8.1.1 If the value of a message selector is an empty string, the value is treated as a null and indicates that there is no message selector for the message consumer. section.3.8.1.1 The order of evaluation of a message selector is from left to right within precedence level. Parentheses can be used to change this order. section.3.8.1.1 A string literal is enclosed in single quotes, with an included single quote represented by doubled single quote; for example, 'literal' and 'literal''s'.
String literals use the Unicode character encoding.
section.3.8.1.1
An exact numeric literal is a numeric value without a decimal point, such as 57, -957, +62; numbers in the range of Java long are supported. Exact numeric literals use the Java integer literal syntax. section.3.8.1.1 An approximate numeric literal is a numeric value in scientific notation, such as 7E3 and -57.9E2, or a numeric value with a decimal, such as 7., -95.7, and +6.2; numbers in the range of Java double are supported. Approximate literals use the Java floating-point literal syntax. section.3.8.1.1 A boolean literal is one of TRUE or FALSE. section.3.8.1.1 An identifier is an unlimited-length character sequence that must begin with a Java identifier start character; all following characters must be Java identifier part characters. An identifier start character is any character for which the method Character.isJavaIdentifierStart returns true. This includes '_' and '$'. An identifier part character is any character for which the method Character.isJavaIdentifierPart returns true. section.3.8.1.1 Identifiers are case sensitive. section.3.8.1.1 Identifiers cannot be the words NULL, TRUE, FALSE, NOT, AND, OR, BETWEEN, LIKE, IN, IS, or ESCAPE. These are case-insensitive reserved words. section.3.8.1.1 Reserved words are case-insensitive. section.3.8.1.1 The conversions that apply to the get methods for properties do not apply when a property is used in a message selector expression. For example, suppose you set a property as a string value, as in the following:
myMessage.setStringProperty("NumberOfOrders", "2");
The following expression in a message selector would evaluate to false, because a string cannot be used in an arithmetic expression: "NumberOfOrders > 1"
section.3.8.1.1
Message header field references are restricted to JMSDeliveryMode, JMSPriority, JMSMessageID, JMSTimestamp, JMSCorrelationID, and JMSType. JMSMessageID, JMSCorrelationID, and JMSType values may be null and if so are treated as a NULL value. TODO - need to test some of these in code section.3.8.1.1 Any name beginning with 'JMSX' is a JMS defined property name.
Any name beginning with 'JMS_' is a provider-specific property name.
Any name that does not begin with 'JMS' is an application-specific property name.
NOTE: cannot realistically test JMS_ properties.
section.3.8.1.1
Whitespace is the same as that defined for Java: space, horizontal tab, form feed and line terminator. section.3.8.1.1 A selector is a conditional expression; a selector that evaluates to true matches; a selector that evaluates to false or unknown does not match. section.3.8.1.1 Arithmetic expressions are composed of themselves, arithmetic operations, identifiers with numeric values, and numeric literals. section.3.8.1.1 Conditional expressions are composed of themselves, comparison operations, logical operations, identifiers with boolean values, and boolean literals. section.3.8.1.1 Logical operators in order of precedence:
  • NOT
  • AND
  • OR
section.3.8.1.1
Comparison operators in order of precedence:
  • =
  • >
  • >=
  • <
  • <=
  • <> (not equal)
section.3.8.1.1
Arithmetic operators in order of precedence are:
  • +, - (unary)
  • *, / (multiplication and division)
  • +, - (addition and subtraction)
section.3.8.1.1
Only like type values can be compared. One exception is that it is valid to compare exact numeric values and approximate numeric values (the type conversion required is defined by the rules of Java numeric promotion). If the comparison of non-like type values is attempted, the value of the operation is false. If either of the type values evaluates to NULL, the value of the expression is unknown. section.3.8.1.1 Boolean comparison is restricted to = and <> section.3.8.1.1 String comparison is restricted to = and <> Two strings are equal if and only if they contain the same sequence of characters. section.3.8.1.1 BETWEEN expressions are of the form: arithmetic-expr1 [NOT] BETWEEN arithmetic-expr2 and arithmetic-expr3 section.3.8.1.1 IN expressions are of the form: identifier [NOT] IN (string-literal1, string-literal2, ...) where identifier has a String or NULL value. If identifier is NULL, the value of the operation is unknown. TODO - add tests where identifier is known to be a non-string value section.3.8.1.1 LIKE expressions are of the form: identifier [NOT] LIKE pattern-value [ESCAPE escape-character] where identifier has a String value; pattern-value is a string literal where '_' stands for any single character; '%' stands for any sequence of characters, including the empty sequence, and all other characters stand for themselves. The optional escape-character is a single-character string literal whose character is used to escape the special meaning of the '_' and '%' in pattern-value. section.3.8.1.1 IS expressions are of the form: identifier IS [NOT] NULL The IS NULL form tests for a null header field value or a missing property value. The IS NOT NULL form tests for the existence of a non-null header field value or property value The IS NULL and IS NOT NULL operators convert an unknown header or property value into the respective TRUE and FALSE values. section.3.8.1.1 section.3.8.1.2 JMS providers are required to verify the syntactic correctness of a message selector at the time it is presented. A method providing a syntactically incorrect selector must result in a JMS InvalidSelectorException. section.3.8.1.1 Arithmetic operations must use Java numeric promotion. section.3.8.1.1 Header fields and property values may be NULL. Comparison or arithmetic with an unknown value always yields an unknown value. section.3.8.1.2 The AND operator evaluates as follows:
ANDTFU
TTFU
FFFF
UUFU
3-4
section.3.8.1.2
The OR operator evaluates as follows:
ORTFU
TTTT
FTFU
UTUU
3-5
section.3.8.1.2
The NOT operator evaluates as follows:
NOT
TF
FT
UU
3-6
section.3.8.1.2
When used in a message selector JMSDeliveryMode is treated as having the values 'PERSISTENT' and 'NON_PERSISTENT'. section.3.8.1.3 Date and time values should use the standard Java long millis value. When a date or time literal is included in a message selector, it should be an integer literal for a millis value. section.3.8.1.3 When creating a connection, a client may specify its credentials as a name/password. JMSSecurityException must be thrown when a provider rejects a user name/password submitted by a client section.4.3.1 section.7.3 The facility to explicitly set a connection's client identifier is not a mechanism for overriding the identifier that has been administratively configured. It is provided for the case where no administratively specified identifier exists. If one does exist, an attempt to change it by setting it must throw an IllegalStateException. section.4.3.2 If a client explicitly sets the client identifer it must do this immediately after creating the connection and before any other action on the connection is taken. After this point, setting the client identifier is a programming error that should throw an IllegalStateException. section.4.3.2 The client state identified by a client identifier can be in use by only one client at a time. A JMS provider must prevent concurrently executing clients from using it. This prevention may take the form of JMSExceptions thrown when such use is attempted; it may result in the offending client being blocked; or some other solution. A JMS provider must insure that such attempted 'sharing' of an individual client state does not result in messages being lost or doubly processed. TODO - don't handle the blocked scenario section.4.3.2 When a Connection is created, it is in stopped mode. That means that no messages are being delivered to it. section.4.3.3 No messages are delivered by a connection to its client until it has been started. section.4.3.3 Stopping a connection has no effect on its ability to send messages. section.4.3.4 A stop method call must not return until delivery of messages has paused. This means a client can rely on the fact that none of its message listeners will be called and all threads of control waiting for receive to return will not return with a message until the connection is restarted. If MessageListeners are running when stop is invoked, stop must wait until all of them have returned before it may return. While these MessageListeners are completing, they must have the full services of the connection available to them. TODO - test behaviour of sending messages while a listener is active, using a different session (i.e, not from the listener - undefined?) TODO - add test where a thread stops a connection and another starts it as the stop is in progress. section.4.3.5 The receive timers for a stopped connection continue to advance, so receives may time out and return a null message while the connection is stopped. section.4.3.5 Stopping a stopped connection is ignored. section.4.3.5 Starting a started connection is ignored. section.4.3.5 A close terminates all pending message receives on the connection's session's consumers. The receives may return with a message or null depending on whether or not there was a message available at the time of the close. section.4.3.5 If one or more of the connection's session's message listeners is processing a message at the point when connection close is invoked, all the facilities of the connection and its sessions must remain available to those listeners until they return control to the JMS provider. section.4.3.5 Once a connection has been closed, an attempt to use it or its sessions or their message consumers and producers must throw an IllegalStateException (calls to the close method of these objects must be ignored). section.4.3.5 If a connection is closed, there is no need to close its constituent objects. The connection close is sufficient to signal the JMS provider that all resources for the connection should be released. TODO: probably the only meaningful way to test this in a provider independent fashion is to attempt to use a temporary destination created by the closed connection, on another connection. This should throw InvalidDestinationException? section.4.3.5 Closing a connection must roll back the transactions in progress on its transacted sessions. section.4.3.5 Closing a connection does NOT force an acknowledgement of client-acknowledged sessions. section.4.3.5 It is valid to continue to use message objects created or received after a connection has been closed with the exception of a received message's acknowledge method. Invoking the acknowledge method of a received message must throw an IllegalStateException. section.4.3.5 Closing a closed connection must NOT throw an exception. section.4.3.5 Closing a transacted session must roll back its transaction in progress. section.4.4.1 Closing a client-acknowledged session does NOT force an acknowledge. section.4.4.1 Once a session has been closed, an attempt to use it or its message consumers and producers must throw an IllegalStateException (calls to the close method of these objects must be ignored). section.4.4.1 It is valid to continue to use message objects created or received via the session, with the exception of a received message'acknowledge method. Invoking the acknowledge method of a received message must throw an IllegalStateException. section.4.4.1 Closing a closed session must NOT throw an exception. section.4.4.1 A close terminates all pending message receives on the connection's session's consumers. The receives may return with a message or null depending on whether or not there was a message available at the time of the close. section.4.4.1 If one or more of the connection's session's message listeners is processing a message at the point when connection close is invoked, all the facilities of the connection and its sessions must remain available to those listeners until they return control to the JMS provider. section.4.4.1 Each transacted session supports a single series of transactions. Each transaction groups a set of produced messages and a set of consumed messages into an atomic unit of work. In effect, transactions organize a session's input message stream and output message stream into series of atomic units. When a transaction commits, its atomic unit of input is acknowledged and its associated atomic unit of output is sent. section.4.4.7 If a transacted session is rolled back, its produced messages are destroyed and its consumed messages are automatically recovered. section.4.4.7 With the DUPS_OK_ACKNOWLEDGE session acknowledgement mode, the session lazily acknowledges the delivery of messages. This is likely to result in the delivery of some duplicate messages if JMS fails, so it should be used only by consumers that are tolerant of duplicate messages. Its benefit is the reduction of session overhead achieved by minimizing the work the session does to prevent duplicates. section.4.4.11 With the AUTO_ACKNOWLEDGE session acknowledgement mode, the session automatically acknowledges a client's receipt of a message when it has either successfully returned from a call to receive or the MessageListener it has called to process the message successfully returns. section.4.4.11 With the CLIENT_ACKNOWLEDGE session acknowledgement mode, a client acknowledges a message by calling the message's acknowledge method. Acknowledging a consumed message automatically acknowledges the receipt of all messages that have been delivered by its session. section.4.4.11 A session's recover method is used to stop a session and restart it with its first unacknowledged message. In effect, the session's series of delivered messages is reset to the point after its last acknowledged message. The messages it now delivers may be different from those that were originally delivered due to message expiration and the arrival of higher-priority messages.
A session must set the redelivered flag of messages it redelivers due to a recovery.
section.4.4.11 section.3.4.7
A TransactionInProgressException exception is thrown when an operation is invalid because a transaction is in progress. For instance, attempting to call Session.commit() when a session is part of a distributed transaction. section.7.3 A TransactionRolledBackException exception must be thrown when a call to Session.commit() results in a rollback of the current transaction. section.7.3 A message can be acknowledged after its message consumer has closed as message acknowledgement is performed at the session level TODO - need to test this for single message acknowledgement via CLIENT_ACKWNOWLEDGE etc http://java.sun.com/products/jms/faq.html#msg_ack_close A session serializes all asynchronous delivery of messages. While the session is busy executing one listener, all other messages to be asynchronously delivered to the session must wait.
Invoking commit() on a non-transacted session should throw IllegalStateException http://java.sun.com/products/jms/javadoc-102a/javax/jms/Session.html#commit() section.7.3 Invoking rollback() on a non-transacted session should throw IllegalStateException http://java.sun.com/products/jms/javadoc-102a/javax/jms/Session.html#rollback() Invoking recover() on a transacted session should throw IllegalStateException http://java.sun.com/products/jms/javadoc-102a/javax/jms/Session.html#recover() If not specified, the default time-to-live for a producer equals 0 http://java.sun.com/products/jms/javadoc-102a/javax/jms/MessageProducer.html#getTimeToLive() http://java.sun.com/products/jms/javadoc-102a/javax/jms/MessageProducer.html#setTimeToLive() A client can specify a default time-to-live for messages sent by a message producer, to be used when a time-to-live isn't specified per message.

Note: the specification doesn't mention min or max values for time-to-live, or if any exceptions will be thrown if an invalid time-to-live is specified.

http://java.sun.com/products/jms/javadoc-102a/javax/jms/MessageProducer.html http://java.sun.com/products/jms/javadoc-102a/javax/jms/TopicPublisher.html#publish(javax.jms.Message) http://java.sun.com/products/jms/javadoc-102a/javax/jms/TopicPublisher.html#publish(javax.jms.Topic,%20javax.jms.Message) http://java.sun.com/products/jms/javadoc-102a/javax/jms/QueueSender.html#send(javax.jms.Message) http://java.sun.com/products/jms/javadoc-102a/javax/jms/QueueSender.html#send(javax.jms.Queue,%20javax.jms.Message)
When a message is sent, JMSDestination is ignored. After completion of the send it holds the destination object specified by the sending method. When a message is received, its destination value must be equivalent to the value assigned when it was sent. section.3.4.1 section.3.4.11 When a message is sent, JMSMessageID is ignored. When the send method returns it contains a provider-assigned value. section.3.4.3 section.3.4.11 All JMSMessageID values must start with the prefix 'ID:' section.3.4.3 The JMSCorrelationID header field may be used to link one message with another. It can contain a provider-specific message ID, an application-specific string, or a provider-native byte[] value. The application-specific string must not start with the 'ID:' prefix: this is reserved for provider generated messages Ids. section.2.10 section.3.4.5 section.3.4.11 If a provider supports the native concept of correlation ID, a JMS client may need to assign specific JMSCorrelationID values to match those expected by non-JMS clients. A byte[] value is used for this purpose. JMS providers without native correlation ID values are not required to support byte[] values - in this case setJMSCorrelationIDAsBytes() and getJMSCorrelationIDAsBytes() may throw java.lang.UnsupportedOperationException. section.3.4.5 If a client receives a message with the JMSRedelivered indicator set, it is likely, but not guaranteed, that this message was delivered but not acknowledged in the past. In general, a provider must set the JMSRedelivered message header field of a message whenever it is redelivering a message. section.3.4.7 section.3.4.11 The JMSRedelivered header field has no meaning on send and is left unassigned by the sending method. section.3.4.7 When a message is sent, its expiration time is calculated as the sum of the time-to-live value specified on the send method and the current GMT value. On return from the send method, the message's JMSExpiration header field contains this value. section.3.4.9 When a message is received its JMSExpiration header field contains the expiration as that on send. section.3.4.9 If the time-to-live is specified as zero, expiration is set to zero to indicate that the message does not expire. section.3.4.9 When GMT is later than an undelivered message's expiration time, the message should be destroyed. Clients should not receive messages that have expired; however, JMS does not guarantee that this will not happen. section.3.4.9 The JMSReplyTo header field contains a Destination supplied by a client when a message is sent. It is the destination where a reply to the message should be sent.
Messages sent with a null JMSReplyTo value may be a notification of some event or they may just be some data the sender thinks is of interest.
section.2.10
When a message is created, its message body and properties may be set.
An identifier is an unlimited-length character sequence that must begin with a Java identifier start character; all following characters must be Java identifier part characters. An identifier start character is any character for which the method Character.isJavaIdentifierStart returns true. An identifier part character is any character for which the method Character.isJavaIdentifierPart returns true. section.3.8.1.1 Identifiers cannot be the words NULL, TRUE, FALSE, NOT, AND, OR, BETWEEN, LIKE, IN, IS, or ESCAPE. These are case-insensitive reserved words. section.3.8.1.1 Identifiers are case sensitive. section.3.8.1.1 Property values can be boolean, byte, short, int, long, float, double, and String. section.3.5.2 The setObjectProperty method accepts values of Boolean, Byte, Short, Integer, Long, Float, Double and String. An attempt to use any other class must throw a JMS MessageFormatException.
The getObjectProperty method only returns values of null, Boolean, Byte, Short, Integer, Long, Float, Double and String. A null value is returned if a property by the specified name does not exist.
section.3.5.5 section.3.5.8
User properties may not be modified by the provider implied Properties support the following conversion table. The marked cases must be supported. The unmarked cases must throw the JMS MessageFormatException.
The String to numeric conversions must throw the java.lang.NumberFormatException if the numeric's valueOf() method does not accept the String value as a valid representation. A value set as the row type can be read as the column type.
 booleanbyteshort intlongfloatdoubleString
boolean X       X
byte XX XX   X
short  X XX   X
int    XX   X
long     X   X
float      XX X
double       X X
StringXXX XXXX X
section.3.5.4 table.3-2
Attempting to read a null value as a Java primitive type must be treated as calling the primitive's corresponding valueOf(String) conversion method with a null value. section.3.5.4 section.3.5.8 The order of property values is not defined. To iterate through a message's property values, use getPropertyNames to retrieve a property name enumeration and then use the various property get methods to retrieve their values. The getPropertyNames method does not return the names of the JMS standard header fields. section.3.5.6 After sending a message, a client may retain and modify it without affecting the message that has been sent. The same message object may be sent multiple times.
When a message is received its body is read only. If an attempt is made to change them, a MessageNotWriteableException must be thrown. If its properties or body are subsequently cleared, they are in the same state as a newly created message. TODO - need to test in transaction context
The clearBody method of Message resets the value of the message body to the empty initial message value as set by the message type's create method provided by Session. Clearing a message's body does not clear its property entries. When a message is cleared, its message body and properties may be set.
Clearing a message's properties leaves the message with an empty set of properties. New property entries can then be both created and read. Clearing a message's property entries does not clear the value of its body.
When the message is first created, the body of the message is in write-only mode. If a client attempts to read a message in write-only mode, a MessageNotReadableException is thrown. url.message.bytes MessageEOFException must be thrown when an unexpected end of stream has been reached when a message is being read. section.7.3 The setObject method places a copy of the input in the message.
When the message is first created, the body of the message is in write-only mode. If a client attempts to read a message in write-only mode, a MessageNotReadableException is thrown. url.message.stream MessageEOFException must be thrown when an unexpected end of stream has been reached when a message is being read. section.7.3 If a read method of a BytesMessage throws a MessageFormatException or NumberFormatException, the current position of the read pointer must not be incremented. A subsequent read must be capable of recovering from the exception by re-reading the data as a different type.
NOTE: With the exception of the readUTF() method, it is difficult to conceive test cases for read methods.
  • A provider that implements BytesMessage using a DataInputStream or equivalent, is likely to only throw MessageFormatException for the readUTF() method.
    The other likely exceptions are MessageEOFException for stream overruns, and JMSException for any other error.
  • As BytesMessage does not support conversion, NumberFormatException is unlikely to be thrown.
section.3.11.3
If a read method of a StreamMessage throws a MessageFormatException or NumberFormatException, the current position of the read pointer must not be incremented. A subsequent read must be capable of recovering from the exception by re-reading the data as a different type. section.3.11.3 table.3-7 A MapMessage is a message whose body contains a set of name-value pairs where names are Strings and values are Java primitive types. The entries can be accessed sequentially by enumerator or randomly by name. The order of the entries is undefined. section.3.11 MapMessage supports the following conversion table. The marked cases must be supported. The unmarked cases must throw a JMS MessageFormatException. The String to numeric conversions must throw a java.lang.NumberFormatException if the numeric's valueOf() method does not accept the String value as a valid representation. MapMessage must implement the String to boolean conversion as specified by the valueOf(String) method of Boolean as defined by the Java language.
A value written as the row type can be read as the column type.
 booleanbyteshort charintlongfloatdouble Stringbyte[]
boolean X         X 
byte XX  XX   X 
short  X  XX   X 
char    X     X 
int     XX   X 
long      X   X 
float       X XX 
double         XX 
StringXXX  XXX XX 
byte[]           X
section.3.11.3 table.3-7
For MapMessage, attempting to read a null value as a Java primitive type must be treated as calling the primitive's corresponding valueOf(String) conversion method with a null value. Since char does not support a String conversion, attempting to read a null value as a char must throw NullPointerException. section.3.11.3 Getting a MapMessage field for a field name that has not been set is handled as if the field exists with a null value. section.3.11.3 StreamMessage supports the following conversion table. The marked cases must be supported. The unmarked cases must throw a JMS MessageFormatException. The String to numeric conversions must throw a java.lang.NumberFormatException if the numeric's valueOf() method does not accept the String value as a valid representation. StreamMessage must implement the String to boolean conversion as specified by the valueOf(String) method of Boolean as defined by the Java language.
A value written as the row type can be read as the column type.
 booleanbyteshort charintlongfloatdouble Stringbyte[]
boolean X         X 
byte XX  XX   X 
short  X  XX   X 
char    X     X 
int     XX   X 
long      X   X 
float       X XX 
double         XX 
StringXXX  XXX XX 
byte[]           X
section.3.11.3 table.3-7
MapMessage field names are case sensitive.
NOTE: the specification does not explicitly mention this requirement, but it is in keeping with property name requirements.
implied
For StreamMessage, attempting to read a null value as a Java primitive type must be treated as calling the primitive's corresponding valueOf(String) conversion method with a null value. Since char does not support a String conversion, attempting to read a null value as a char must throw NullPointerException.
NOTE: the specification is not explicit on the behaviour of invoking writeBytes() or writeString() with a null value, but an acceptable policy is to throw a NullPointerException. This is in keeping with the behaviour of DataOutputStream.
section.3.11.3
A provider must be prepared to accept, from a client, a message whose implementation is not one of its own. A message with a 'foreign' implementation may not be handled as efficiently as a provider's own implementation; however, it must be handled.
Note that if the foreign message implementation contains a JMSReplyTo header field that is set to a foreign destination implementation, the provider is not required to handle or preserve the value of this field.
section.3.12
The JMS message interfaces provide read/get methods for accessing objects in a message body. All of these methods must be implemented to return a copy of the accessed objects. section.3.12 The JMS message interfaces provide read/get methods for accessing message object properties. All of these methods must be implemented to return a copy of the accessed objects. section.3.12 When clearBody is called on a BytesMessage, the body of the message is in write-only mode.
If clearBody is called on a message in read-only mode, the message body is cleared and the message is in write-only mode.
url.message.bytes
Refer to javadoc http://java.sun.com/products/jms/javadoc-102a/javax/jms/BytesMessage.html#readBytes(byte[]) Refer to javadoc http://java.sun.com/products/jms/javadoc-102a/javax/jms/BytesMessage.html#readBytes(byte[], int) Refer to javadoc http://java.sun.com/products/jms/javadoc-102a/javax/jms/BytesMessage.html#writeObject() Refer to javadoc http://java.sun.com/products/jms/javadoc-102a/javax/jms/MapMessage.html#setObject() Refer to javadoc http://java.sun.com/products/jms/javadoc-102a/javax/jms/MapMessage.html#itemExists() Refer to javadoc http://java.sun.com/products/jms/javadoc-102a/javax/jms/MapMessage.html#getMapNames() When clearBody is called on a StreamMessage, the body of the message is in write-only mode.
If clearBody is called on a message in read-only mode, the message body is cleared and the message is in write-only mode.
url.message.stream
Refer to javadoc http://java.sun.com/products/jms/javadoc-102a/javax/jms/StreamMessage.html#writeObject() Refer to javadoc http://java.sun.com/products/jms/javadoc-102a/javax/jms/StreamMessage.html#writeBytes(byte[]) Refer to javadoc http://java.sun.com/products/jms/javadoc-102a/javax/jms/StreamMessage.html#writeBytes(byte[], int, int) Refer to javadoc http://java.sun.com/products/jms/javadoc-102a/javax/jms/StreamMessage.html#readBytes JMSXGroupID and JMSXGroupSeq are standard properties clients should use if they want to group messages. All providers must support them. JMSXGroupID is a string property. JMSXGroupSeq is an int property, starting at 1. @todo - need to verify if the range is applicable section.3.5.9 table.3-3 JMS reserves the 'JMSX' property name prefix for JMS defined properties. Unless noted otherwise, support for these properties is optional. The Enumeration ConnectionMetaData.getJMSXPropertyNames() method returns the names of the JMSX properties supported by a connection. Properties that may only be set by the provider include JMSXUserID, JMSXAppID, JMSXDeliveryCount, JMSXProducerTXID, JMSXConsumerTXID, JMSXRcvTimestamp and JMSXState. section.3.5.9 table.3-3 ConnectionMetaData provides a list of the JMS defined property names supported by the connection. This must include JMSXGroupID and JMSXGroupSeq section.3.5.9 In some cases, a connection may both publish and subscribe to a topic. The subscriber NoLocal attribute allows a subscriber to inhibit the delivery of messages published by its own connection. section.6.11 If a client needs to receive all the messages published on a topic, including the ones published while the subscriber is inactive, it uses a durable TopicSubscriber. JMS retains a record of this durable subscription and insures that all messages from the topic's publishers are retained until either they are acknowledged by this durable subscriber or they have expired. section.6.11.1 section.6.3 Sessions with durable subscribers must always provide the same client identifier. In addition, each client must specify a name that uniquely identifies (within client identifier) each durable subscription it creates. section.6.11.1 Only one session at a time can have a TopicSubscriber for a particular durable subscription. section.6.11.1 section.4.3.2 A client can change an existing durable subscription by creating a durable TopicSubscriber with the same name and a new topic and/or message selector. Changing a durable subscription is equivalent to deleting and recreating it. section.6.11.1 TopicSessions provide the unsubscribe method for deleting a durable subscription created by their client. This deletes the state being maintained on behalf of the subscriber by its provider. It is erroneous for a client to delete a durable subscription while it has an active TopicSubscriber for it or while a message received by it is part of a current transaction or has not been acknowledged in the session. (Note: this last sentence suggests that a provider doesn't need to check that a client can remove a subscription) section.6.11.1 For application servers, connections provide a special facility for creating a ConnectionConsumer. The messages it is to consume are specified by a destination and a message selector. In addition, a ConnectionConsumer must be given a ServerSessionPool to use for processing its messages. A maxMessages value is specified to limit the number of messages a ConnectionConsumer may load at one time into a ServerSession's session. section.8.2.4 If a destination is removed via the provider's administration interface, and subsequently recreated, all messages to that destination must also be removed. implied