26.2. Writing JMS Operations Within an Application Component

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.

26.2.1. Accessing the Connection Factory

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:

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>

26.2.2. Accessing the Destination Object

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>

26.2.3. Writing JMS Operations

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.

NoteNote
 

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();
}

26.2.4. Transactions and JMS Sessions Within an Application Component

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.

26.2.5. Authentication with JMS

If your JMS implementation performs user authentication, the following methods can be used on connection factories:

NoteNote
 

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.