Skip Headers

Oracle® Application Server Containers for J2EE Enterprise JavaBeans Developer's Guide
10g Release 2 (10.1.2)
Part No. B15505-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

Client Access of MDB

The client sends a message to the MDB through a JMS Destination. The client can retrieve the JMS Destination and connection factory either through using its explicit name or by a logical name. The following sections describe both methods for retrieving the JNDI name.

Using an Explicit Name for the JNDI Lookup

Within your client, you can use the actual JNDI name to retrieve the JMS Destination objects. Both OracleAS JMS and Oracle JMS have their own naming methodology, as explained in the following sections:

Accessing OracleAS JMS Destination with Explicit JNDI Names

The JNDI lookup for OracleAS JMS requires the OracleAS JMS Destination and connection factory as defined by you within the jms.xml file, prepended with "java:comp/env/." See "JMS Destination Object Configuration" to see how the queue and topic for OracleAS JMS is configured.


Note:

If you decide to use logical names instead, you would use the same JNDI syntax. Logical names are recommended, because they are portable. See "Using a Logical Name When Client Accesses the MDB" for more information.

To lookup a queue in the JNDI lookup for the testResourceProvider example using OracleAS JMS are as follows:

//Lookup the Queue
queue = (Queue)jndiContext.lookup("java:comp/env/jms/Queue/rpTestQueue");

//Lookup the Queue Connection factory
queueConnectionFactory = (QueueConnectionFactory)
    jndiContext.lookup("java:comp/env/jms/Queue/myQCF");

To lookup a topic, you would have slightly different strings, designating a topic rather than a queue, as follows:

//Lookup the Topic
topic = (Topic)jndiContext.lookup("java:comp/env/jms/Topic/rpTestTopic");

//Lookup the Connection factory
topicConnectionFactory = (TopicConnectionFactory)
       jndiContext.lookup("java:comp/env/jms/Topic/myTCF");

Note that the same names for the topic and the connection factory are used in the client's configuration, the jms.xml, and the MDB deployment descriptors.

Accessing Oracle JMS Destination with Explicit JNDI Names

The JNDI lookup—when using Oracle JMS—requires the Oracle JMS Destination and connection factory syntax, which is the same naming convention as described for the connection-factory-location and destination-location attributes in "Specify the Destination and Connection Factory".


Note:

If you decide to use logical names instead, you would use the same JNDI syntax. See "Using a Logical Name When Client Accesses the MDB" for more information.

In your JNDI lookup, the implementation would be as follows for both a queue and a topic (See Example 9-6 for the full example):

/* Retrieve an Oracle JMS Queue through JNDI */
queue = (Queue) ic.lookup("java:comp/resource/myProvider/Queues/rpTestQueue");
/*Retrieve the Oracle JMS Queue connection factory */
queueConnectionFactory = (QueueConnectionFactory) ic.lookup
     ("java:comp/resource/myProvider/QueueConnectionFactories/myQCF");

/* Retrieve an Oracle JMS Topic through JNDI */
topic = (Topic) ic.lookup("java:comp/resource/myProvider/Topics/rpTestTopic");
/*Retrieve the Oracle JMS Topic connection factory */
topicConnectionFactory = (TopicConnectionFactory) ic.lookup
     ("java:comp/resource/myProvider/TopicConnectionFactories/myTCF");

Steps for Sending a Message to an MDB

Whether or not the implementation uses logical names or the actual JNDI names, the client sends a JMS message to the MDB by doing the following:

  1. Retrieve both the configured JMS Destination and its connection factory using a JNDI lookup.

  2. Create a connection from the connection factory. If you are receiving messages for a queue, then start the connection.

  3. Create a session over the connection.

  4. Providing the retrieved JMS Destination, create a sender for a queue, or a publisher for a topic.

  5. Create the message.

  6. Send out the message using either the queue sender or the topic publisher.

  7. Close the queue session. Close the connection for either JMS Destination types.

Example 9-6 Servlet Client Sends Message to Queue

public final class testResourceProvider extends HttpServlet
{
  private String resProvider = "myResProvider";
  private HashMap msgMap = new HashMap();
  Context ctx = new InitialContext();

 public void doGet(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException
 {
    doPost(req, res);
 }

 public void doPost(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException
 {
   //Retrieve the name of the JMS provider from the request, which is 
   // to be used in creating the JNDI string for retrieval
    String rp = req.getParameter ("provider");
    if (rp != null)
      resProvider = rp;

    try
    {
      // 1a. Look up the Queue Connection Factory
      QueueConnectionFactory qcf = (QueueConnectionFactory)
               ctx.lookup ("java:comp/resource/" + resProvider + 
               "/QueueConnectionFactories/myQCF"); 
      // 1b. Lookup the Queue  
      Queue queue = (Queue) ctx.lookup ("java:comp/resource/" + resProvider +
                                       "/Queues/rpTestQueue");
      
      // 2 & 3. Retrieve a connection and a session on top of the connection
      // 2a. Create queue connection using the connection factory.
      QueueConnection qconn = qcf.createQueueConnection();
      // 2a. We're receiving msgs, so start the connection.
      qconn.start();

      // 3. create a session over the queue connection.
      QueueSession qsess = qconn.createQueueSession(false,
                                                   Session.AUTO_ACKNOWLEDGE);

       // 4. Since this is for a queue, create a sender on top of the session. 
       //This is used to send out the message over the queue.
      QueueSender snd = sess.createSender (q);

    drainQueue (sess, q);
    TextMessage msg = null;

    /* Send msgs to queue.  */
    for (int i = 0; i < 3; i++)
    {
      // 5. Create message
      msg = sess.createTextMessage();
      msg.setText ("TestMessage:" + i);

       // set property of the recipient to be the MDB         //and set the reply destination.
      msg.setStringProperty ("RECIPIENT", "MDB");
      msg.setJMSReplyTo(q);
      
      //6. send the message using the sender.
      snd.send (msg);

      // You can store the messages IDs and sent-time  in a map (msgMap),
      // so that when messages are received, you can verify if you 
      // *only* received those messages that you were
       // expecting. See receiveFromMDB() method where msgMap gets used.         
      msgMap.put (msg.getJMSMessageID(), new Long (msg.getJMSTimestamp()));
    }

    // receive a reply from the MDB.
    receiveFromMDB (sess, q);

     //7. Close sender, session, and connection for queue
     snd.close();
     sess.close();
     qconn.close();
    }
    catch (Exception e)
    {
      System.err.println ("** TEST FAILED **"+ e.toString());
      e.printStackTrace();
    }
    finally
    {
    }
 }

  /*
   * Receive any msgs sent to us via the MDB
   */
  private void receiveFromMDB (QueueSession sess, Queue q)
    throws Exception
  {
    //The MDB sends out a message (as a reply) to this client. The MDB sets
    // the receipient as CLIENT. Thus, we will only receive msgs that have 
    // RECIPIENT set to 'CLIENT'
    QueueReceiver rcv = sess.createReceiver (q, "RECIPIENT = 'CLIENT'");

    int nrcvd = 0;
    long trtimes = 0L;
    long tctimes = 0L;
    // First msg needs to come from MDB. May take  a little while 
    //Receiving Messages
    for (Message msg = rcv.receive (30000); msg != null;
         msg = rcv.receive (30000))
    {
      nrcvd++;

      String rcp = msg.getStringProperty ("RECIPIENT");
      // Verify if msg in message Map  
      // We check the msgMap to see if this is the message that we are 
      // expecting.
      String corrid = msg.getJMSCorrelationID();
      if (msgMap.containsKey(corrid))
      {
        msgMap.remove(corrid);
      }
      else
      {
        System.err.println ("** received unexpected message
                              [" + corrid + "] **");
      }
    }
    rcv.close();
  }

  /*
   * Drain messages from queue
   */
  private int drainQueue (QueueSession sess,
                           Queue q)
    throws Exception
  {

    QueueReceiver rcv = sess.createReceiver (q);
    int nrcvd = 0;

    /*
     * First drain any old msgs from queue
     */
    for (Message msg = rcv.receive(1000);
         msg != null;
         msg = rcv.receive(1000))
      nrcvd++;
    rcv.close();

    return nrcvd;
  }
}

Using a Logical Name When Client Accesses the MDB

If you want to use a logical name in your client application code, then define the logical name in one of the following XML files:

  • A standalone Java client—in the application-client.xml file

  • An EJB that acts as a client—the ejb-jar.xml file

  • For JSPs and servlets that act as clients—the web.xml file

Map the logical name to the actual name of the topic or queue name in the OC4J deployment descriptors.

You can create logical names for the connection factory and Destination objects, as follows:

  • The connection factory is identified in the client's XML deployment descriptor file within a <resource-ref> element.

    • The logical name that you want the connection factory to be identified as is defined in the <res-ref-name> element.

    • The connection factory class type is defined in the <res-type> element as either javax.jms.QueueConnectionFactory or javax.jms.TopicConnectionFactory.

    • The authentication responsibility (Container or Bean) is defined in the <res-auth> element.

    • The sharing scope (Shareable or Unshareable) is defined in the <res-sharing-scope> element.

  • The JMS Destination—the topic or queue—is identified in a <resource-env-ref> element.

    • The logical name that you want the topic or queue to be identified as is defined in the <resource-env-ref-name> element.

    • The Destination class type is defined in the <resource-env-ref-type> element as either javax.jms.Queue or javax.jms.Topic.

The following shows an example of how to specify logical names for a topic.

<resource-ref>
  <res-ref-name>myTCF</res-ref-name>
  <res-type>javax.jms.TopicConnectionFactory</res-type>
  <res-auth>Container</res-auth>
  <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
<resource-env-ref>
  <resource-env-ref-name>rpTestTopic</resource-env-ref-name>  
  <resource-env-ref-type>javax.jms.Topic</resource-env-ref-type>
</resource-env-ref>

Then, you map the logical names to actual names in the OC4J deployment descriptors. The actual names, or JNDI names, are different in OracleAS JMS than in Oracle JMS. However, the mapping is defined in one of the following files:

  • For a standalone Java client—the orion-application-client.xml

  • For an EJB acting as a client—the orion-ejb-jar.xml

  • For JSPs and servlets acting as a client—the orion-web.xml file.

The logical names in the client's deployment descriptor are mapped as follows:

  • The logical name for the connection factory defined in the <resource-ref> element is mapped to its JNDI name in the <resource-ref-mapping> element.

  • The logical name for the JMS Destination defined in the <resource-env-ref> element is mapped to its JNDI name in the <resource-env-ref-mapping> element.

See the following sections for how the mapping occurs for both OracleAS JMS and Oracle JMS:

JNDI Naming for OracleAS JMS

The JNDI name for the OracleAS JMS Destination and connection factory is defined by you within the jms.xml file. As shown in "JMS Destination Object Configuration", the JNDI names for the topic and the topic connection factory are as follows:

  • The JNDI name for the topic is "jms/Topic/rpTestTopic."

  • The JNDI name for the topic connection factory is "jms/Topic/myTCF."

Prepend both of these names with "java:comp/env/" and you have the mapping in the orion-ejb-jar.xml file as follows:

<resource-ref-mapping          name="myTCF"         location="java:comp/env/jms/Topic/myTCF">
</resource-ref-mapping>

<resource-env-ref-mapping        name="rpTestTopic"         location="java:comp/env/jms/Topic/rpTestTopic"></resource-env-ref-mapping>

JNDI Naming for Oracle JMS

The JNDI naming for Oracle JMS Destination and connection factory objects is the same name that was specified in the orion-ejb-jar.xml file for the MDB as described in "Specify the Destination and Connection Factory".

The following example maps the logical names for the connection factory and topic to their actual JNDI names. Specifically, the topic defined logically as "rpTestTopic" in the ejb-jar.xml file is mapped to its JNDI name of "java:comp/resource/cartojms1/Topics/rpTestTopic."

<resource-ref-mapping          name="myTCF"         location="java:comp/resource/myProvider/TopicConnectionFactories/myTCF">
</resource-ref-mapping>

<resource-env-ref-mapping        name="rpTestTopic"         location="java:comp/resource/myProvider/Topics/rpTestTopic"></resource-env-ref-mapping>

Client Sends JMS Message Using Logical Names

Once the resources have been defined, the client sends a JMS message to the MDB by doing the following:

  1. Retrieve both the configured JMS Destination and its connection factory using a JNDI lookup.

  2. Create a connection from the connection factory. If you are receiving messages for a queue, start the connection.

  3. Create a session over the connection.

  4. Providing the retrieved JMS Destination, create a sender for a queue, or a publisher for a topic.

  5. Create the message.

  6. Send out the message using either the queue sender or the topic publisher.

  7. Close the queue session. Close the connection for either JMS Destination types.

Example 9-7 JSP Client Sends Message to a Topic

The method of sending a message over a topic is almost the same. Instead of creating a queue, you create a topic. Instead of creating a sender, you create subscribers.

The following JSP client code sends a message over a topic to the MessageBean MDB. The code uses logical names, which should be mapped in the OC4J deployment descriptor.

<%@ page import="javax.jms.*, javax.naming.*, java.util.*" %>
<%

//1a. Lookup the MessageBean topic
jndiContext = new InitialContext();
topic = (Topic)jndiContext.lookup("rpTestTopic");

//1b. Lookup the MessageBean Connection factory
topicConnectionFactory = (TopicConnectionFactory)
   jndiContext.lookup("myTCF");

//2 & 3. Retrieve a connection and a session on top of the connection
topicConnection = topicConnectionFactory.createTopicConnection();
topicSession = topicConnection.createTopicSession(true,
                                     Session.AUTO_ACKNOWLEDGE);

//5. Create the publisher for any messages destined for the topic
topicPublisher = topicSession.createPublisher(topic);

//6. Send out the message
for (int  ii = 0; ii < numMsgs; ii++)
{
  message = topicSession.createBytesMessage();
  String  sndstr = "1::This is message " + (ii + 1) + " " + item;
  byte[]  msgdata = sndstr.getBytes();
  message.writeBytes(msgdata);
  
  topicPublisher.publish(message);
  System.out.println("--->Sent message: " + sndstr);
}

//7. Close publisher, session, and connection for topic
topicPublisher.close();
topicSession.close();
topicConnection.close();

%>
Message sent!