To send (or synchronously receive) JMS messages, an application component requires access to JMS-administered objects (that is, to connection factories for creating connections to JMS resources, and to destination objects (queue or topic), which are the JMS entities used as destinations within JMS sending operations). Both are made available through JNDI by the JMS provider administration facility.
You can find a sample JMS application in $JONAS_ROOT/examples/src/jms/; it is described in Section 26.6 A JMS EJB Example.
The EJB specification introduces the concept of resource manager connection factory references. This concept also appears in the J2EE v1.4 specification. It is used to create connections to a resource manager. To date, three types of resource manager connection factories are considered:
DataSource objects (javax.sql.DataSource) represent connection factories for JDBC connection objects.
JMS connection factories. The connection factories for JMS connection objects are:
javax.jms.ConnectionFactory
javax.jms.QueueConnectionFactory
javax.jms.TopicConnectionFactory.
Java Mail connection factories. The connection factories for Java Mail connection objects are javax.mail.Session or javax.mail.internet.MimePartDataSource.
The connection factories of interest here are the second type, which should be used to get JMS connection factories.
Note that starting with JMS 1.1, it is recommended that you use only the javax.jms.ConnectionFactory (rather than javax.jms.QueueConnectionFactory or javax.jms.TopicConnectionFactory). However, the JMS 1.1 implementation is fully backwards-compatible and existing applications will work as-is.
The standard deployment descriptor should contain the following resource-ref element:
<resource-ref> <res-ref-name>jms/conFact</res-ref-name> <res-type>javax.jms.ConnectionFactory</res-type> <res-auth>Container</res-auth> </resource-ref> |
This means that the programmer will have access to a ConnectionFactory object using the JNDI name java:comp/env/jms/conFact. The source code for obtaining the factory object is the following:
ConnectionFactory qcf = (ConnectionFactory) ctx.lookup("java:comp/env/jms/conFact"); |
The mapping to the actual JNDI name of the connection factory (as assigned by the JMS provider administration tool), CF in the example, is defined in the JOnAS-specific deployment descriptor with the following element:
<jonas-resource> <res-ref-name>jms/conFact</res-ref-name> <jndi-name>CF</jndi-name> </jonas-resource> |
Accessing a JMS destination within the code of an application component requires using a Resource Environment Reference, which is represented in the standard deployment descriptor as follows:
<resource-env-ref> <resource-env-ref-name>jms/stockQueue</resource-env-ref-name> <resource-env-ref-type>javax.jms.Queue<resource-env-ref-type> </resource-env-ref> |
The application component's source code should contain:
Queue q = (Queue) ctx.lookup("java:comp/env/jms/stockQueue"); |
The mapping to the actual JNDI name (for example, "myQueue") is defined in the JOnAS-specific deployment descriptor in the following way:
<jonas-resource-env> <resource-env-ref-name>jms/stockQueue</resource-env-ref-name> <jndi-name>myQueue<jndi-name> </jonas-resource-env> |
A typical method performing a message-sending JMS operation looks like the following:
void sendMyMessage() { ConnectionFactory cf = (ConnectionFactory) ctx.lookup("java:comp/env/jms/conFact"); Queue queue = (Queue) ctx.lookup("java:comp/env/jms/stockQueue"); Connection conn = cf.createConnection(); Session sess = conn.createSession(true, Session.AUTO_ACKNOWLEDGE); MessageProducer mp = sess.createProducer((Destination)queue); ObjectMessage msg = sess.createObjectMessage(); msg.setObject("Hello"); sender.send(msg); sess.close(); conn.close(); } |
It is also possible for an application component to synchronously receive a message. Here is an EJB method that performs synchronous message reception on a queue:
public String recMsg() { ConnectionFactory cf = (ConnectionFactory) ctx.lookup("java:comp/env/jms/conFact"); Queue queue = (Queue) ctx.lookup("java:comp/env/jms/stockQueue"); Connection conn = cf.createConnection(); Session sess = conn.createSession(true, Session.AUTO_ACKNOWLEDGE); MessageConsumer mc = sess.createConsumer((Destination)queue); conn.start(); ObjectMessage msg = (ObjectMessage) mc.receive(); String msgtxt = (String) msg.getObject(); sess.close(); conn.close(); return msgtxt; } |
A method that performs JMS operations should always contain the session create and close statements, as follows:
public void doSomethingWithJMS (...) { ... session = connection.createSession(...); ... // JMS operations session.close(); } |
The contained JMS operations will be a part of the transaction, if there is one, when the JOnAS server executes the method.
Note | |
---|---|
Never send and receive a particular message in the same transaction because JMS sending operations are performed only at commit time. |
The previous examples illustrate point-to-point messaging. However, application components can also be developed using the publish/subscribe JMS API (that is, using the Topic instead of the Queue destination type). This offers the capability of broadcasting a message to several message consumers at the same time.
The following example illustrates a typical method for publishing a message on a JMS topic and demonstrates how interfaces have been simplified since JMS 1.1.
public void sendMsg(java.lang.String s) { ConnectionFactory cf = (ConnectionFactory) ictx.lookup("java:comp/env/jms/conFactSender"); Topic topic = (Topic) ictx.lookup("java:comp/env/jms/topiclistener"); Connection conn = cf.createConnection(); Session session = conn.createSession(true, Session.AUTO_ACKNOWLEDGE); MessageConsumer mc = session.createConsumer((Destination)topic); ObjectMessage message = session.createObjectMessage(); message.setObject(s); mc.send(message); session.close(); conn.close(); } |
JMS session creation within an application component will result in different behaviors, depending on whether the session is created at execution time within or outside a transaction. In fact, the parameters of the createSession(boolean transacted, int acknowledgeMode) method are never taken into account.
If the session creation occurs outside a transaction, the parameters is considered as being transacted = false and acknowlfor example, Mode = AUTO_ACKNOWLEDGE. This means that each operation of the session is immediately executed.
If the session creation occurs inside a transaction, the parameters have no meaning, the session may be considered as transacted, and the commit and rollback operations are handled by the JOnAS server at the level of the associated XA resource.
If your JMS implementation performs user authentication, the following methods can be used on connection factories:
The createConnection(String userName, String password) method can be used on ConnectionFactory
The createQueueConnection(String userName, String password) method can be used on QueueConnectionFactory
The createTopicConnection(String userName, String password) method can be used on TopicConnectionFactory
Note | |
---|---|
Starting with JMS 1.1, it is recommended that you use only the javax.jms.ConnectionFactory (rather than javax.jms.QueueConnectionFactory or javax.jms.TopicConnectionFactory). However, the JMS 1.1 implementation is fully backwards-compatible and existing applications will work as-is. |