The generic JMSJCA adapter is packaged and specialized for the following connectors:
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:
| Parameter name | Meaning |
|---|---|
| ConnectionURL | default value for connectionURL |
| UserName | default username |
| Password | default password |
| MBeanObjectName | MBeanObjectName: 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. |
| MBeanServerDomain | MBean 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. |
| Options | See below |
| Parameter name | Meaning |
|---|---|
| ConnectionURL | connectionURL. Takes precedence over the value specified in the generic section of ra.xml. |
| UserName | username. Takes precedence over the value specified in the generic section of ra.xml. |
| Password | password. Takes precedence over the value specified in the generic section of ra.xml. |
| ClientId | the client id, used in Connection.setClientID() |
| ProducerPooling | boolean 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. |
| IdleTimeout | this 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. |
| Options | switches and options, see below |
| Parameter name | required? | Meaning |
|---|---|---|
| ConnectionURL | not required | connectionURL. Takes precedence over the value specified in the generic section of ra.xml. |
| UserName | not required | username. Takes precedence over the value specified in the generic section of ra.xml. |
| Password | not required | password. Takes precedence over the value specified in the generic section of ra.xml. |
| ClientId | not required | the 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. |
| destination | mandatory | name of the queue or topic that messages should be read from |
| destinationType | mandatory | should be either javax.jms.Queue or javax.jms.Topic |
| subscriptionDurability | depends | applies only to topics. Should be set to either Durable or NonDurable |
| subscriptionName | depends | in case the subscriptionDurability is set to Durable, this parameter must be specified and must indicate the name of the durable subscriber. |
| ConcurrencyMode | not required | either serial, cc, or sync. See below. |
| endpointPoolMaxSize | not required | In 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. |
| MBeanName | not required | MBeanObjectName: 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. |
| selector | not required | specifies a JMS message selector (optional) |
| Options | not required | switches and options, see below |
| RedeliveryHandling | not required | see below. |
| BatchSize | not required | see below. (Set to a number greater than 1 to turn on batching) |
| HoldUntilAck | not required | see below. (Set to 1 to turn on this special mode) |
| ContextName | not required | Before 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. |
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".
The presedence order for outbound connections is as follows: 1) createConnection(username, password), 2) at the connection factory level, and 3) at the connector level.
The presedence order for MDBs is as follows: 1) at the activation spec level, and 2) at the connector level.
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.
| Parameter value | Meaning |
|---|---|
| serial | Uses one asynchronous listener; the JMS thread is used to invoke the onMessage() method. |
| cc | Provides for concurrent processing by using connection consumer mode. Messages are dispatched to the WorkManager. Messages may be processed out of order. |
| sync | Provides 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.
| Parameter name | in/out | Meaning |
|---|---|---|
| JMSJCA.NoXA | in/out | if set to true, this indicates that the resource adapter should not use XA; it should assume that the container will not call getXAResource() on the managed connection. This feature can be used when the resource adapter is used outside of the application server, or if the application wants control over the transactional behavior. |
| JMSJCA.LocatorClass | in/out | Specifies 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.redeliveryredirect | in | If set to true, in the case of messages being sent to dead letter queue, messages will be redirected rather than copied. |
| JMSJCA.redeliveryhandling | in | specifies the behavior of the dead letter queue. See below. |
| JMSJCA.concurrencymode | in | allows 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.ACC | out | if 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.IgnoreTx | out | if set to true, the resource adapter will ignore the isTransacted parameter to the method createSession(isTransacted, ackmode) and equivalent functions. The default is the opposite of JMSJCA.ACC. This property can also be set as a system property. |
| JMSJCA.BypassRA | out | if 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.Strict | out | if 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. |
Options can be specified in:
| Method | Meaning |
|---|---|
| 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.
| Attribute | Meaning |
|---|---|
| ActivationSpec | A dump of the values in the activation spec |
| NActiveEndpoints | Number of active MDBs, i.e. number of threads that are currently in onMessage() |
| NConfiguredEndpoints | Number of MDBs specified in the activation spec |
| NHighestActiveEndpoints | Highest number of active MDBs reached sofar |
| NMessages | Total number of messages delivered, i.e. the number of times onMessage() was invoked |
| NTotalEndpoints | Current number of MDBs in the pool |
| Stats | snapshot of performance numbers |
| Method | Meaning |
|---|---|
| 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. |
| getStatus | indicates 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. |
| getProperties | returns a String specifying configuration parameters. |
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.
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.
stcms://localhost:18007?JMSJCA.redeliveryhandling=5:1000; 10:5000
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:
3:25; 5:50; 10:100; 20:1000; 50:5000
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
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.
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().
message.setBooleanProperty("JMSJCA.setRollbackOnly", true);
message.acknowledge();
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);
}
}
}
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);
}
}