What is JMSJCA

J2EE 1.4 specifies J2EE Connector Architecture 1.5 as the basic mechanism to integrate JMS providers with J2EE application servers. JMSJCA is an implementation of the Java Connector Architecture 1.5 that is used to integrate JMS providers within J2EE application servers. Not only does JMSJCA supports several different JMS providers, it also supports a number of advanced features not found in other connectors.

The generic JMSJCA adapter is packaged and specialized for the following connectors:

Release information

5.1.0

5.1.1

5.1.2

5.1.3

Features

JMSJCA adapters provide the following advanced features:

How to use a JMSJCA adapter

There are two ways to use a JMSJCA adapter with an EAR:
  1. the adapter can be packaged in the EAR as a "local RAR"
  2. the adapter can be deployed in the application server as a "global RAR"

In either case, to use of outbound connections, a mapping must be made in the deployment descriptor of the EJB or servlet that ties the JNDI names of the connection factories to names in the ENC (Environment Naming Context). The application code can then lookup the JMS connection factory and create outbound connections.

Example:

TopicConnection topicConn = null;
try {
    TopicConnectionFactory factory = (TopicConnectionFactory) context.lookup("java:comp/env/jms/TCF");
    topicConn = factory.createTopicConnection();
    TopicSession topicSession = topicConn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
    topic = (Topic) context.lookup("jms/topic1");
    TopicPublisher publisher = topicSession.createPublisher(topic);
    TextMessage txtMsg = topicSession.createTextMessage("Hello world");
    publisher.publish(txtMsg);
} finally {
    if (topicConn != null) {
        topicConn.close();
    }
}

Note that because a JMS connection is a transactional resource:

Configuration

The connector is configured through ra.xml. The configuration is divided into these sections:
  1. for each MDB there is an activation spec; it is defined in ra.xml, but the values for the activation spec parameters are specified in the ejb-jar.xml of the EJB.
  2. for each connection factory there is a section in the ra.xml in which parameters can be specified
  3. the connector can have default values that will be used if values are not set in the connection factory settings or activation spec. These values are specified at the top of ra.xml.

Generic parameters

The following parameters can be specified at the connector level, i.e. at the top of ra.xml.
Parameter nameMeaning
ConnectionURLdefault value for connectionURL
UserNamedefault username
Passworddefault password
MBeanObjectNameMBeanObjectName: name of the MBean that the adapter should create. The MBean will provide access to statistical info and a relay MBean for management of destinations in the JMS server.
MBeanServerDomainMBean server domain: JMX name for the MBeanServer to be used to register the RA MBean in. Not used if no MBean name is specified. When left blank or unspecified, the default MBeanServer will be used.
OptionsSee below

Connection factory configuration

Parameter nameMeaning
ConnectionURLconnectionURL. Takes precedence over the value specified in the generic section of ra.xml.
UserNameusername. Takes precedence over the value specified in the generic section of ra.xml.
Passwordpassword. Takes precedence over the value specified in the generic section of ra.xml.
ClientIdthe client id, used in Connection.setClientID()
ProducerPoolingboolean that indicates if producers are pooled by the connector. For some JMS providers JMS producers (topic-publishers and queue-senders) are expensive to create because it may involve creating a socket connection. When ProducerPooling is turned on, the socket resources of a producer will not be closed when the application closes the producer. Instead, the producer will be returned to a pool that is tied to the session. The next time the application uses a producer on the session, it will be reused from the pool.
IdleTimeoutthis parameter is used for connection validation. If a connection is not used successfully for a period longer than the IdleTimeout period, the connection is marked as invalid. "Successfully" is defined as a msg was sent or received without an exception from the underlying JMS implementation.
Optionsswitches and options, see below

Configuration of the activation spec

Parameter namerequired?Meaning
ConnectionURLnot requiredconnectionURL. Takes precedence over the value specified in the generic section of ra.xml.
UserNamenot requiredusername. Takes precedence over the value specified in the generic section of ra.xml.
Passwordnot requiredpassword. Takes precedence over the value specified in the generic section of ra.xml.
ClientIdnot requiredthe client id passed to setClientID)(). Note that many JMS providers require a client id to be set in order to use durable topics. If this value is omitted or left blank, a client ID will be automatically generated based on the durable subscription name.
destinationmandatoryname of the queue or topic that messages should be read from. To indicate that this is the name of an object that should be looked up in JNDI, prefix the name with lookup://. If this prefix is not found, the queue or topic will be created using the approach most suitable for the JMS server, typically by calling createQueue(name) or createTopic(name) See release notes of individual adapters for more information.
destinationTypemandatoryshould be either javax.jms.Queue or javax.jms.Topic
subscriptionDurabilitydependsapplies only to topics. Should be set to either Durable or NonDurable
subscriptionNamedependsin case the subscriptionDurability is set to Durable, this parameter must be specified and must indicate the name of the durable subscriber.
ConcurrencyModenot requiredeither serial, cc, or sync. See below.
endpointPoolMaxSizenot requiredIn the case of concurrent processing, this value (integer) specifies the number of MDBs that can be used to process messages concurrently. This should match the value specied in the application server specific deployment descriptor that specifies the number of MDBs the bean pool.
MBeanNamenot requiredMBeanObjectName: name of the MBean that the adapter should create. The MBean will provide access to statistical info and a relay MBean for management of destinations in the JMS server.
selectornot requiredspecifies a JMS message selector (optional)
Optionsnot requiredswitches and options, see below
RedeliveryHandlingnot requiredsee below.
BatchSizenot requiredsee below. (Set to a number greater than 1 to turn on batching)
HoldUntilAcknot requiredsee below. (Set to 1 to turn on this special mode)
ContextNamenot requiredBefore the inbound connector calls the onMessage() method on an MDB, it will first log a message to the Logger with name com.stc.EnterContext. This entry in the activation spec defines the contents of the message. After the onMessage() method has returned, the same message (i.e. the value of ContextName), will be logged to the com.stc.ExitContext logger. The parameter ContextName may be left blank or may be omitted; in that case the value of ContextName is not logged to com.stc.EnterContext and com.stc.ExitContext. The Java CAPS application server interprets the com.stc.EnterContext and com.stc.ExitContext specially, and will actually not log the message (i.e. the value of ContextName), but will prepend the value of ContextName to all log entries that are logged by the application in the MBD.

ConnectionURL

The connector typically uses a URL as the connectivity information to connect to the JMS server, even if that JMS server normally doesn't use a URL format. The format is of the form
     protocol://server:port?key1=value1&key2=value2
The query string is optional and contains both properties for the JMS server as well as for the connector. See also the section on Options below.

The ConnectionURL can be specified at the connector level (i.e. top of ra.xml), but also for each activation spec. This allows multiple MDBs to use the same connector, but connect to different JMS servers. The ConnectionURL can also be specified for each connection factory. This is useful for global connectors: to connect to multiple JMS servers, one can specify a different ConnectionURL for each connection factory. For embedded connectors this is slightly different: the connection factory is configured in the ra.xml, and the number of connection factories in ra.xml is limited to exactly one per connectionfactory-interface class. This class must be one of the three JMS factory classes. Hence, the number of connection factories is limited to three per connector. Hence, if no global connectors are used, a separate embedded connector has to be used for each distinct JMS server used in an EAR. An alternative construct to using one different embedded connector for each distinct JMS server is by using a special facility in JMSJCA in which the username is overloaded: see below "Overloaded username".

Authentication

At each place where the connection URL can be specified, it is also necessary to specify the credentials to connect to that JMS server: hence the username and password can be specified at the connector level, the connection factory level, and at the activation spec level. Further, for outbound connections, the application code can specify a username and password when calling ConnectionFactory.createConnection(username, password) or one of the equivalents for queue and topic. See also the section "Overloaded username".

The precedence order for outbound connections is as follows: 1) createConnection(username, password), 2) at the connection factory level, and 3) at the connector level.

The precedence order for MDBs is as follows: 1) at the activation spec level, and 2) at the connector level.

Overloaded username

Normally the connectionURL is tied to a connection factory, so for each JMS server there should be a separate connection factory. The application code then has to choose the correct connection factory that is tied to the desired JMS server.

A special feature of JMSJCA is that the ConnectionURL can also be specified in the application code when creating a connection through ConnectionFactory.createConnection(username, password) or one of the equivalents for queue and topic. If the username can be recognized as a ConnectionURL, e.g. if the username starts with stcms:// or stcmss:// for STCMS, the username is interpreted as a ConnectionURL rather than a username. The username can still be specified: the query parameters username and password will be read from the ConnectionURL. The password can also be specified in the password parameter to createConnection(username, password).

Example:
ConnectionFactory.createConnection("stcms://blue:18008?user=X", "Y") will create a connection to the STCMS server on BLUE at port 18008 using the username "X" and the password "Y". This is equivalent to ConnectionFactory.createConnection("stcms://blue:18008?user=X&password=Y", null). If the username is not specified, e.g. as in ConnectionFactory.createConnection("stcms://blue:18008, null), the username is obtained through the normal presedence rules, i.e. from the connection factory level specification or the connector.

Connections to JMS servers specified in the username parameter are pooled in the same pool as the "normal" connections in the connector pool.

Concurrency

The JMSJCA connector can deliver messages to multiple MDBs concurrently. The following concurrency modes are available (specify one of these values for the ConcurrencyMode-parameter) in the activation spec:
Parameter valueMeaning
serialUses one asynchronous listener; the JMS thread is used to invoke the onMessage() method.
ccProvides for concurrent processing by using connection consumer mode. Messages are dispatched to the WorkManager. Messages may be processed out of order.
syncProvides for multiple synchronous receivers that call receive(TIMEOUT) in a loop. This mode is mandatory for some implementations that do not properly implement the connection consumer mode (CC), or do not allow the XA start() method to be called from within the onMessage() method. A consequence is that for Topics, there will be no concurrent processing in this mode.

The default value for the ConcurrencyMode-parameter is serial.

Administrative objects

The ra.xml defines two administrative objects: one for a javax.jms.Queue, and the other one for a javax.jms.Topic. These are generic objects that can be bound in JNDI. When they are created and bound in JNDI, they may not represent physical destinations in the JMS server yet. Only when the application code uses an administrative object is the object actually turned into a JMS destination specific for the JMS server in use. This happens in a manner that is specific for the type of JMS server. For example, for the RAWL adapter, the name of an administrative Queue is interpreted as a name bound in the same JNDI provider as is specified for the adapter.

The destination in an activation spec can also be specified as an administrative object. To indicate that the destination parameter in an activation spec denotes an object that should be looked up, prefix the name with lookup://.

Example

A JNDI adapter is configured to use a JNDI provider on server X. An administrative object is created and bound in the application server's JNDI using the name orders. The name attribute of the administrative object is specified as jndi://queues/q1234. Assume the application code looks like this:
    Destination q = (Destination) new InitialContext().lookup("orders");
    session.createProducer(q).send(session.createTextMessage("hello 1"));
    session.createProducer(q).send(session.createTextMessage("hello 2"));
In the first send() method in this code fragment, the destination is looked up in the JNDI provider at server X using the lookup-name queues/q1234. Because destinations are cached in the adapter, in the second send() method, the cached destination object is used.

In this example, the activation spec has the destination attribute has the value lookup://orders, the destination object is looked up in a similar fashion in the JNDI provider at server X using the lookup-name queues/q1234. If on the other hand the destination attribute has the value orders, the destination object is obtained using createQueue("orders") or createTopic("orders").

RA Options

The following RA options can be defined
Parameter namein/outMeaning
JMSJCA.NoXAin/outif set to true, this indicates that the resource adapter should not use XA. This can be used in case the JMS provider is not configured to use XA. This feature can also be used when the resource adapter is used outside of the application server. See the note on transaction control below.
JMSJCA.LocatorClassin/outSpecifies the Java class name of the class that will be used to access the transaction manager in the application server. The transaction manager is used in case of temporary destinations (in order to delete them when the connection closes) and when messages are moved to the dead letter queue. The default value will most likely suffice.
JMSJCA.redeliveryredirectinIf set to true, in the case of messages being sent to dead letter queue, messages will be redirected rather than copied.
JMSJCA.redeliveryhandlinginspecifies the behavior of the dead letter queue. See below.
JMSJCA.concurrencymodeinallows the concurrency mode to be overridden. Values are sync, CC, or serial. This is useful in particular cases (e.g. FIFO modes in STCMS) where the default concurrency mode does not suffice.
JMSJCA.ACCoutif set to true this indicates that the resouce adapter should behave as if it is running inside a client container. This means that the resource adapter will not be under the control of a transaction manager. The default is false. This property can also be set as a system property.
JMSJCA.IgnoreTxoutif set to true, the resource adapter will ignore the isTransacted parameter to the method createSession(isTransacted, ackmode) and equivalent functions and always change this parameter to isTransacted=true and the ackmode parameter is set to TRANSACTED. The default value is the opposite of JMSJCA.ACC. This property can also be set as a system property.
JMSJCA.BypassRAoutif set to true, this indicates that factories should not delegate to the resource adapter, but will instead delegate to the "native" JMS connection factory directly. The default is false. This property can also be set as a system property.
JMSJCA.Strictoutif set to true, the adapter will behave as close to the J2EE spec as possible. This property can also be set as a system property. See notes of specific adapters.
JMSJCA.sepin/outTo allow multiple properties to be specified in one single line (useful for some administrative consoles that limit the user input to one line), this options allows for a character to be specified that will be used to delimit multiple options. Example: "JMSJCA.sep=,JMSJCA.NoXA=true,JMSJCA.ACC=true" specifies two options: JMSJCA.NoXA = true and JMSJCA.ACC = true. Note that the separator can be escaped with a backslash in case it needs to be used as part of an option-value. Example: "JMSJCA.sep=*JMSJCA.NoXA=true*queuepattern=Q.\*" yields two values: JMSJCA.NoXA=true and queuepattern=Q.*

Options can be specified in:

  1. the Options field in the general section of the ra.xml; the options field is a serialized Java properties set. In short: this field consists of key-value pairs. One pair per line. A key is separated from the value using a = sign. Comments are indicated using ! or #.
  2. the Options field of the connection factory in the ra.xml, or in the activation spec of the ejb-jar.xml. Format: see 1. Takes precedence over 1.
  3. the connection URL in the form of query parameters. Takes precedence over 2.

JMX Management

Each JMSJCA Resource Adapter can specify the name of an MBean. This MBean can be used to access some generic management properties of the adapter.
MethodMeaning
getJMSServerMBean()returns the ObjectName of the MBean that provides management capabilities of the contents of destinations in the JMS server.
getJMSServerType()returns the type of the JMS server, e.g. STCMS.

Also, for each activation (i.e. MDB deployment), the JMSJCA connector can register an MBean. This MBean can be used to start/stop delivery of messages to the MDBs and can be used to extract performance data out of the connector. The name is specified in the MBeanName parameter of the activation spec.

AttributeMeaning
ActivationSpecA dump of the values in the activation spec
NActiveEndpointsNumber of active MDBs, i.e. number of threads that are currently in onMessage()
NConfiguredEndpointsNumber of MDBs specified in the activation spec
NHighestActiveEndpointsHighest number of active MDBs reached sofar
NMessagesTotal number of messages delivered, i.e. the number of times onMessage() was invoked
NTotalEndpointsCurrent number of MDBs in the pool
Statssnapshot of performance numbers

MethodMeaning
getJMSServerMBean()returns the ObjectName of the MBean that provides management capabilities of the contents of destinations in the JMS server.
getJMSServerType()returns the type of the JMS server, e.g. STCMS.
getStatusindicates if the connector is "Up" (i.e. connected to the JMS server, and potentially delivering messages to MDBs), "Down" (i.e. no connection exists to the JMS server), "Connecting" (i.e. the adapter is trying to establish a connection to the JMS server; the status of a connector immediately after activation is always "Connecting"), or "Disconnecting" (i.e. the connector is disconnecting from the JMS server and may be waiting for all threads to return from their onMessage() methods.
getPropertiesreturns a String specifying configuration parameters.

Transaction control

Outbound connections, default behavior (spec compliant)

By default the resource adapter assumes that the RA is used within an application server and that the RA is deployed with XATransaction support. Consequently the RA assumes that the container will call getXAResource() on the managed connection and will manage the transaction. Example:
Connection c = fact.createConnection();
Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE);

Outbound connections, special behavior (non spec compliant)

Using the option JMSJCA.NoXA=true, the default behavior can be changed. The RA is still assuming that it is used within within an application server and that the RA is deployed with XATransaction support, and that the container will call getXAResource() on the managed connection and may try to manage the transaction. However, the RA does not use an XAConnectionFactory, but tries to emulate XA as good as it can within the constraints imposed by the application code. The session may be transacted or non-transacted.

Transacted mode: This is the default mode: a call to Connection.createSession(isTransacted, ackmode is defaulted to c.createSession(true, Session.SESSION_TRANSACTED). The XA emulation will propagate only the second phase of the transaction commit protocol to the session, i.e. commit and rollback are propagated to the transacted session; the first phase is ignored. This implies that transactional integrity is not guaranteed: if Session.commit() or Session.rollback() fail, the transaction may be left in an inconsistent state. Note that the application code can call Session.commit() or Session.rollback() directly; in that case the transaction managed by the container is bypassed completely, and the transaction may be inconsistent.

Non transacted mode: To use this mode, set JMSJCA.IgnoreTx=false(default is true), and call Connection.createSession(false, Session.AUTO_ACKNOWLEDGE) (the values CLIENT_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE may also be used). The XA emulation will not propagate anything of the container managed transaction to the session. This means that the session is used completely outside of the transaction managed by the container. There is no transactional integrity.

Inbound

Container Managed Transactions: by default the RA will use an XAConnectionFactory and enlist the XAResource in the container managed transaction.
Bean Managed Transactions: the RA will use a non-XA ConnectionFactory and use a transacted session. The received message will only be rolled back if the MDB throws an exception.
Special behavior: if the option JMSJCA.NoXA=true is specified, the RA will use Bean Managed Transaction semantics even in the case of a Container Managed Transaction deployment.

Redelivery handling (deadletter queue)

A poison message is a message that fails to be processed time and time again, thereby stopping other messages from being processed, and hogging the CPU so that other requests cannot be processed.

How it works

For each message that is received, the redelivery-flag is checked. If that flag is set, it will go through the redelivery handling process. This process uses a a cache of msgids of messages that have the JMSRedelivered flag set. This cache keeps a count for each of these messages of how often they were "seen", i.e. how often they were redelivered. Based on this count, a particular Action can be invoked. Actions are delaying, moving or deleting the message.

The msgid cache is not persistent, nor is it shared between multiple activations. This means that if a message was seen 10 times with the redelivered flag set, and the project is undeployed, the redelivery count will be set to zero when the project is deployed again. Also, if there are multiple application servers reading from the same queue, a message may be redelivered 10 times to one application server, and 10 times to the other application server, and both activations will see a count of 10 instead of 20.

The msgid cache is limited to 5000 entries; when this limit is reached, the oldest msgids are flushed from the cache. "Oldest" means least recently seen.

When to choose which action?

A message is typically redelivered because of an error in the processing of the message by the application code. This error may be permanent or transient. Delaying delivery of a redelivered message is useful to save CPU cycles instead of letting the message "spin" rapidly. If the error is transient, the message will eventually "go through". If the error is permanent, moving messages to a different destination may be a better approach. If the message is not valuable, deleting the message is another option.

Configuration

Specification of what actions to undertake when the message is repeatedly redelivered is done through a specially formatted string. The string has this format:
   format := entry[; entry]*
   entry := idx ":" action
   idx := number (denotes the n-th time a msg was seen)
   action := number (denotes delay in ms) | "delete" | "move"(args)
   move := "queue"|"topic" | "same" ":" destname
   destname :=  any string, may include "$" which will be replaced with the original
       destination name.
Example:
    5:1000; 10:5000; 50:move(queue:mydlq)
This causes no delay up to the 5th delivery; a 1000 ms delay is invoked when the message is seen the 5th, 6th, 7th, 8th, and 9th time. A 5 second delay is invoked when the msg is invoked the 10th, 11th, ..., 49th time. When the msg is seen the 50th time the msg is moved to a queue with the name "mydlq".

If the messages were received from "Queue1" and if the string was specified as

    5:1000; 10:5000; 50:move(queue:dlq$oops)
the messages would be moved to the destination "dlqQueue1oops": the special character "$" denotes the original destination name. Instead of "queue" one can also specify "topic" or "same". The latter denotes a queue if the message was received from a queue, or can denote a topic if the message was received from a topic.

Another example:

    5:1000; 10:5000
This causes no delay up to the 5th delivery; a 1000 ms delay is invoked when the message is seen the 5th, 6th, 7th, 8th, and 9th time. A 5 second delay is invoked for each time the message is seen thereafter.

Where redelivery handling is configured

The action string (e.g. 5:1000; 10:5000) can be specified in the RedeliveryHandling field of the activation spec. Alternatively, the string can be specified as an option in either the URL, the Options field in the activation spec or in the Options spec in the ra.xml using the property name JMSJCA.redeliveryhandling. Example:
     stcms://localhost:18007?JMSJCA.redeliveryhandling=5:1000; 10:5000

How messages are moved

Moving messages is done in the same transaction if the transaction is XA. Moving messages is done using auto-commit if the delivery is non-XA.

Moving messages is done by creating a new message of the same type unless the property JMSJCA.redeliveryRedirect is set to true in which case the messages are simply redirected. In the first case, the payload of the new message is set as follows:

Note that copying the payload of an ObjectMessage may cause classloader problems since the context classloader is not properly set. In this case the redelivery handler should be configured to redirect the message instead. The new message will have properties as follows:

Redirecting messages

If moving a message fails, the message is redirected instead. This means that the same unmodified message is sent to the target destination. This behavior can be choosen as default behavior instead of moving by setting the property JMSJCA.redeliveryredirect to true. This can be done in the URL or the Options field in the activation spec or the ra.xml.

How messages are delayed

Invoking a delay takes place by holding the processing thread occupied, that means that while the thread is sleeping, this thread will not be used to process any other messages. This means that the delaying strategy cannot be used to "side-track" messages at no expense. Note that long message delays have no effect on the speed of undeployment. Message delays cannot be longer than 5 seconds. No warning is logged unless the msg delay is divisible by 1000, in which case an INFO message is written to the log indicating that the thead is delaying message delivery.

Default behavior

There is a default behavior for message redelivery handling:
 
3:25; 5:50; 10:100; 20:1000; 50:5000

Batching

When the BatchSize parameter in the activation spec is set to a value greater than one, the resource adapter will deliver multiple messages in one transaction to the MDB.

Supported concurrency modes

This mode is supported in the sync concurrency modes only.

EndOfBatch message

At the end of each batch, the connector delivers an EndOfBatch message to the MDB. Even if the transaction is marked for rollback, or if a message earlier caused an exception, the EndOfBatch message is delivered. Only if the MDB is shutdown by the application server, or if the application server unexpectedly exits, situations may arise where no EndOfBatch message is delivered.

The EndOfBatch message can be recognized using an Object message property with the name JMSJCA.EndOfBatch such that

    message.getObjectProperty("JMSJCA.EndOfBatch")
returns
    Boolean.TRUE

Number of messages in a batch

The connector tries to deliver the number of messages specified in BatchSize in one batch. The EndOfBatch message is added to this number. The actual number of messages is less than or equal to the specified number (plus one for the EndOfBatch message).

Transaction scope

The EndOfBatch message is part of the transaction scope. Rolling back the transaction or throwing an exception from the onMessage() method will cause the batch to be rolled back.

Note that since all messages in a batch are delivered in one transaction, all messages in the batch are rolled back. Therefore, in typical applications, it would be preferable to move faulty messages to an error-queue rather than to throw an exception or mark the transaction for rollback. Note that the redelivery handling feature (see above) works the same on all messages and cannot make a distinction which message in a batch may be faulty.

Threading

It is guaranteed that calls to onMessage() for all messages of the same batch are done in the same thread. However, it is not guaranteed that the calls to onMessage() for all messages of the same batch are done on the same MessageListener or MDB instance -- this depends on the application server.

Hold-for-acknowledge mode (non batch mode)

This mode allows for the processing of a message to be done in a thread that is different from the thread that calls onMessage(). This mode mimics the CLIENT_ACKNOWLEDGE mode in JMS with an extension for multi-threaded processing; this extension deviates from the J2EE 1.4 threading model. The advantage of this mode is that messages can be processed concurrently with fewer threads.

Here is an example that illustrates its intended use:

    // An imaginary way to post a request to a different thread
    private void postRequest(Message m, OnDoneHandler h) {
        // Do something
    }

    // An imaginary callback handler
    public interface OnDoneHandler {
        void onDone(boolean failed) throws Exception;
    };
    
    // The onMessage method
    public void onMessage(final Message m) {
        postRequest(m, new onDoneHander() {
            public void onDone(boolean failed) {
                m.acknowledge();
             }
        });
    }

In this example the RA-thread will call onMessage(), and after it has returned from this method it will not commit/rollback the transaction nor will it return the session to the pool. Instead, these two activities are done when the other thread calls acknowledge().

Supported modes

Acknowledging / rolling back a message

To acknowledge a message, call acknowledge() on the message. To rollback a message, call the setRollbackOnly() method of the Transaction object that controls the delivery of the message. If the MDB was deployed as a Bean managed transaction (BMT) with the transaction-attribute NotSupported, the message was not delivered in a transaction, and there will be no Transaction object. In that case, set the JMSJCA.setRollBackOnly boolean property in the message to true, and then call acknowledge(). E.g.:
message.setBooleanProperty("JMSJCA.setRollbackOnly", true);
message.acknowledge();

Threading and transaction details

Example

The following code snippet illustrates the intended use of the hold-for-ack mode:
    public void onMessage(final Message message) {
        try {
            postRequest(message, new OnDoneHandler() {
                public void onDone(boolean failed) throws Exception {
                    if (failed) { 
                        message.setBooleanProperty("JMSJCA.setRollbackOnly", true);
                    }
                    message.acknowledge();
                }
            });
        } catch (Exception e) {
            // Posting failed; rollback
            try {
                message.setBooleanProperty("JMSJCA.setRollbackOnly", true);
                message.acknowledge();
            } catch (JMSException e1) {
                throw new RuntimeException(e1);
            }
        }
    }    

How to configure

Specify the HoldUntilAck parameter in the activation spec; the value should be "1" to turn on the hold-until-ack mode.

Hold-for-acknowledge mode in batch mode

The hold-for-acknowledge mode can be combined with batch mode. This can lead to even more efficient use of JMS sessions and threads.

Acknowledging / rolling back a message

In addition to what is described above, the following constraints are there for batch mode:

Here is an example:

    public void onMessage(final Message message) {
        try {
            if (message.getObjectProperty("JMSJCA.EndOfBatch") != null) {
                // End of batch
                message.acknowledge();
            } else {
                // Message in middle of batch 
                try {
                    postRequest(message, new OnDoneHandler() {
                        public void onDone(boolean failed) throws Exception {
                            if (failed) { 
                                message.setBooleanProperty("JMSJCA.setRollbackOnly", true);
                            }
                            message.acknowledge();
                        }
                    });
                } catch (Exception e) {
                    // Posting failed; rollback
                    message.setBooleanProperty("JMSJCA.setRollbackOnly", true);
                    message.acknowledge();
                }
            }
        } catch (JMSException e) {
            throw new RuntimeException(e);
        }
    }