26.6. A JMS EJB Example

This example shows an EJB application that combines an Enterprise Bean sending a JMS message and an Enterprise Bean writing a Database (an Entity Bean) within the same global transaction. It is composed of the following elements:

You can find the sample JMS application in $JONAS_ROOT/examples/src/jms/; it is described in Section 26.6 A JMS EJB Example.

26.6.1. The Session Bean Performing JMS Operations

The bean should contain code for initializing the references to JMS administered objects that it will use. To avoid repeating this code in each method performing JMS operations, it can be introduced in the ejbCreate method.

public class EjbCompBean implements SessionBean {
...
ConnectionFactory cf = null;
Topic topic = null;

public void ejbCreate() {
   ....
   ictx = new InitialContext();
   cf = (ConnectionFactory)
      ictx.lookup("java:comp/env/jms/conFactSender");
   topic = (Topic) ictx.lookup("java:comp/env/jms/topiclistener");
}
...
}

All code that is not necessary for understanding the JMS logic (such as exception management) has been removed from the above example.

The JMS-administered objects ConnectionFactory and Topic have been made available to the bean by a resource reference in the first example, and by a resource environment reference in the second example.

The standard deployment descriptor should contain the following element:

<resource-ref>
  <res-ref-name>jms/conFactSender</res-ref-name>
  <res-type>javax.jms.ConnectionFactory</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

<resource-env-ref>
  <resource-env-ref-name>jms/topiclistener</resource-env-ref-name>
  <resource-env-ref-type>javax.jms.Topic</resource-env-ref-type>
</resource-env-ref>

The JOnAS-specific deployment descriptor should contain the following element:

<jonas-resource>
  <res-ref-name>jms/conFactSender</res-ref-name>
  <jndi-name>TCF</jndi-name>
</jonas-resource>

<jonas-resource-env>
  <resource-env-ref-name>jms/topiclistener</resource-env-ref-name>
  <jndi-name>sampleTopic</jndi-name>
</jonas-resource-env>

Note that the EjbComp SessionBean will use the administered objects automatically created by JOnAS in the default JMS configuration.

Because the administered objects are now accessible, it is possible to perform JMS operations within a method. The following occurs in the sendMsg method:

public class EjbCompBean implements SessionBean {
...
public void sendMsg(java.lang.String s) {
    // create Connection, Session and MessageProducer
    Connection conn = null;
    Session session = null;
    MessageProducer mp = null;
    try {
        conn = cf.createConnection();   
        session = conn.createSession(true, Session.AUTO_ACKNOWLEDGE);
        mp = session.createProducer((Destination)topic);
    }
    catch (Exception e) {e.printStackTrace();}

    // send the message to the topic
    try {
        ObjectMessage message;
        message = session.createObjectMessage();
        message.setObject(s);
        mp.send(message);
        session.close();
        conn.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
...
}

This method sends a message containing its String argument.

26.6.2. The Entity Bean

The example uses the simple Entity Bean Account for writing data into a database. Refer to the sample eb, which is described in Chapter 2 Getting Started with JOnAS and in the JOnAS Tutorial.

26.6.3. The Client Application

The client application calls the sendMsg method of the EjbComp bean and creates an AccountImpl Entity Bean, both within the same transaction.

public class EjbCompClient {
...
public static void main(String[] arg) {
...
utx = (UserTransaction) 
  initialContext.lookup("javax.transaction.UserTransaction");
...
home1 = (EjbCompHome) initialContext.lookup("EjbCompHome");
home2 = (AccountHome) initialContext.lookup("AccountImplHome");
...
EjbComp aJmsBean = home1.create();
Account aDataBean = null;
...
utx.begin();
aJmsBean.sendMsg("Hello commit"); // sending a JMS message
aDataBean = home2.create(222, "JMS Sample OK", 0);
utx.commit();

utx.begin();
aJmsBean.sendMsg("Hello rollback"); // sending a JMS message
aDataBean = home2.create(223, "JMS Sample KO", 0);
utx.rollback();
...
}
}

The result of this client execution will be that:

26.6.4. A Pure JMS Client for Receiving Messages

In this example, the messages sent by the EJB component are received by a simple JMS client that is running outside the JOnAS server, but listening for messages sent on the JMS topic "sampleTopic." It uses the ConnectionFactory automatically created by JOnAS named "JCF".

public class MsgReceptor {

static Context ictx = null;
static ConnectionFactory cf = null;
static Topic topic = null;

public static void main(String[] arg) {

    ictx = new InitialContext();
    cf = (ConnectionFactory) ictx.lookup("JCF");
    topic = (Topic) ictx.lookup("sampleTopic");
    ...
    Connection conn = cf.createConnection();       
    Session session = 
           conn.createSession(false, Session.AUTO_ACKNOWLEDGE);  
    MessageConsumer mc = session.createConsumer((Destination)topic);

    MyListenerSimple listener = new MyListenerSimple();
        mc.setMessageListener(listener);
    conn.start();

    System.in.read(); // waiting for messages

    session.close();
    conn.close();
    ...
}
}

public MyListenerSimple implements javax.jms.MessageListener {
   MyListenerSimple() {}

   public void onMessage(javax.jms.Message msg) {
  try {
  if(msg==null)
    System.out.println("Message: message null ");
  else {
    if(msg instanceof ObjectMessage) {
        String m = (String) ((ObjectMessage)msg).getObject();
        System.out.println ("JMS client: received message ======> " + m);
    } else if(msg instanceof TextMessage) {
        String m = ((TextMessage)msg).getText();
        System.out.println ("JMS client: received message ======> " + m);
    }
  }catch(Exception exc) {
      System.out.println("Exception caught :" + exc);
      exc.printStackTrace();
  }
   } 
}