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
 

MDB Using Oracle JMS

The MDB processes incoming asynchronous requests using Oracle JMS (Advanced Queuing), as follows:


Caution:

MDBs only work with certain versions of the Oracle database. See the certification matrix in the JMS chapter of the Oracle Application Server Containers for J2EE Services Guide for more information.

  1. The MDB opens a JMS connection to the database using a data source with a username and password. The data source represents the Oracle JMS provider and uses a JDBC driver to facilitate the JMS connection.

  2. The MDB opens a JMS session over the JMS connection.

  3. Any message for the MDB is routed to the onMessage method of the MDB.

At any time, the client can send a message to the Oracle JMS topic or queue on which MDBs are listening. The Oracle JMS topic or queue is located in the database.


Note:

The entire MDB example is available on OTN from the OC4J sample code page at http://www.oracle.com/technology/tech/java/oc4j/demos/ on the OTN Web site.

Figure 9-2 Demonstration of an MDB Interacting with an Oracle JMS Destination

Demonstration of an MDB interacting with an Oracle JMS destination.
Description of the illustration mdba.gif

The following sections demonstrate an MDB that uses Oracle JMS as the JMS provider.

Install and Configure the JMS Provider

You or your DBA must install Oracle JMS according to theOracle9i Application Developer's Guide—Advanced Queuing for Release 2 (9.2) and generic database manuals. Once you have installed and configured this JMS provider, you must apply additional configuration for each MDB. This includes the following:

  1. You or your DBA should create an RDBMS user through which the MDB connects to the database. Grant this user appropriate access privileges to perform Oracle JMS operations. See "Create User and Assign Privileges".

  2. You or your DBA should create the tables and queues to support the JMS Destination objects. See "Create JMS Destination Objects".


    Note:

    The following sections use SQL for creating queues, topics, their tables, and assigning privileges that is provided within the MDB demo on OTN from the OC4J sample code page at http://www.oracle.com/technology/tech/java/oc4j/demos/ on the OTN Web site.

Create User and Assign Privileges

Create an RDBMS user through which the MDB connects to the database. Grant access privileges to this user to perform Oracle JMS operations. The privileges that you need depend on what functionality you are requesting. Refer to theOracle9i Application Developer's Guide—Advanced Queuing for Release 2 (9.2) for more information on privileges necessary for each type of function.

The following example creates jmsuser, which must be created within its own schema, with privileges required for Oracle JMS operations. You must be a SYS DBA to execute these statements.

DROP USER jmsuser CASCADE ;

GRANT connect, resource,AQ_ADMINISTRATOR_ROLE TO jmsuser IDENTIFIED BY jmsuser ;
GRANT execute ON sys.dbms_aqadm  TO  jmsuser;
GRANT execute ON sys.dbms_aq     TO  jmsuser;
GRANT execute ON sys.dbms_aqin   TO  jmsuser;
GRANT execute ON sys.dbms_aqjms  TO  jmsuser;

connect jmsuser/jmsuser;

You may need to grant other privileges, such as two-phase commit or system administration privileges, based on what the user needs. See the JTA chapter in the Oracle Application Server Containers for J2EE Services Guide for the two-phase commit privileges.

Create JMS Destination Objects

Each JMS provider requires its own method for creating the JMS Destination object. Refer to theOracle9i Application Developer's Guide—Advanced Queuing for Release 2 (9.2) for more information on the DBMS_AQADM packages and Oracle JMS messages types. For our example, Oracle JMS requires the following methods:


Note:

The SQL for creating the tables for the Oracle JMS example is included in the MDB example available on OTN from the OC4J sample code page at http://www.oracle.com/technology/tech/java/oc4j/demos/ on the OTN Web site.

  1. Create the tables that handle the JMS Destination (queue or topic).

    In Oracle JMS, both topics and queues use a queue table. The rpTestMdb JMS example creates a single table: rpTestQTab for a queue.

    To create the queue table, execute the following SQL:

    DBMS_AQADM.CREATE_QUEUE_TABLE(
            Queue_table            => 'rpTestQTab',
            Queue_payload_type     => 'SYS.AQ$_JMS_MESSAGE',
            sort_list => 'PRIORITY,ENQ_TIME',
            multiple_consumers  => false,
            compatible             => '8.1.5');
    
    

    The multiple_consumers parameter denotes whether there are multiple consumers or not; thus, is always false for a queue and true for a topic.

  2. Create the JMS Destination. If you are creating a topic, you must add each subscriber for the topic. The rpTestMdb JMS example requires a single queue—rpTestQueue.

    The following creates a queue called rpTestQueue within the queue table rpTestQTab. After creation, the queue is started.

    DBMS_AQADM.CREATE_QUEUE(
          Queue_name          => 'rpTestQueue',
          Queue_table         => 'rpTestQTab');
    
    DBMS_AQADM.START_QUEUE(
          queue_name         => 'rpTestQueue');
    
    

    If you wanted to add a topic, then the following example shows how you can create a topic called rpTestTopic within the topic table rpTestTTab. After creation, two durable subscribers are added to the topic. Finally, the topic is started and a user is granted a privilege to it.


    Note:

    Oracle AQ uses the DBMS_AQADM.CREATE_QUEUE method to create both queues and topics.

    DBMS_AQADM.CREATE_QUEUE_TABLE(
            Queue_table            => 'rpTestTTab',
            Queue_payload_type     => 'SYS.AQ$_JMS_MESSAGE',
            multiple_consumers  => true,
            compatible             => '8.1.5');
    DBMS_AQADM.CREATE_QUEUE( 'rpTestTopic', 'rpTestTTab');
    DBMS_AQADM.ADD_SUBSCRIBER('rpTestTopic',                          sys.aq$_agent('MDSUB', null, null));
    DBMS_AQADM.ADD_SUBSCRIBER('rpTestTopic',                          sys.aq$_agent('MDSUB2', null, null));
    DBMS_AQADM.START_QUEUE('rpTestTopic');
    

    Note:

    The names defined here must be the same names used to define the queue or topic in the orion-ejb-jar.xml file.

Configure the OC4J XML Files for the JMS Provider

To use the Oracle JMS provider, you must configure the following in the OC4J XML files:

Configure the DataSource

Configure a data source for the database where the Oracle JMS provider is installed. The JMS topics and queues use database tables and queues to facilitate messaging. The type of data source you use depends on the functionality you want.

Transactional Functionality

For no transactions or single-phase transactions, you can use either an emulated or non-emulated data sources. For two-phase commit transaction support, you can use only a non-emulated data source.

Example 9-4 Emulated DataSource With Thin JDBC Driver

The following example contains an emulated data source that uses the thin JDBC driver. To support a two-phase commit transaction, use a non-emulated data source. For differences between emulated and non-emulated data sources, see the Data Source chapter in the Oracle Application Server Containers for J2EE Services Guide.

The example is displayed in the format of an XML definition; see the Oracle Application Server Containers for J2EE User's Guide for directions on adding a new data source to the configuration through the EM tool.

<data-source
  class="com.evermind.sql.DriverManagerDataSource"
  name="OracleDS"
  location="jdbc/emulatedOracleCoreDS"
  xa-location="jdbc/xa/emulatedOracleXADS"
  ejb-location="jdbc/emulatedDS"
  connection-driver="oracle.jdbc.driver.OracleDriver"
  username="jmsuser"
  password="jmsuser"
  url="jdbc:oracle:thin:@myhost.foo.com:1521:mydb"
/>

Customize this data source to match your environment. For example, substitute the host name, port, and SID of your database for mysun:1521:orcl.


Note:

Instead of providing the password in the clear, you can use password indirection. For details, see the Oracle Application Server Containers for J2EE Services Guide.

Identify the JNDI Name of the Oracle JMS Data Source

Identify the JNDI name of the data source that is to be used as the Oracle JMS provider within the <resource-provider> element.

  • If this is to be the JMS provider for all applications (global), configure the global application.xml file.

  • If this is to be the JMS provider for a single application (local), configure the orion-application.xml file of the application.

The following code sample shows how to configure the JMS provider using XML syntax for Oracle JMS.

  • class attribute—The Oracle JMS provider is implemented by the oracle.jms.OjmsContext class, which is configured in the class attribute.

  • property attribute—Identify the data source that is to be used as this JMS provider in the property element. The topic or queue connects to this data source to access the tables and queues that facilitate the messaging.

The following example demonstrates that the data source identified by "jdbc/emulatedDS" is to be used as the Oracle JMS provider. This JNDI name is identified in the ejb-location element in Example 9-4. If this example used a non-emulated data source, then the name would be the same as in the location element.

<resource-provider class="oracle.jms.OjmsContext" name="myProvider">
  <description> OJMS/AQ </description>
  <property name="datasource" value="jdbc/emulatedDS"></property>
</resource-provider>

Create the OC4J-Specific Deployment Descriptor to Use Oracle JMS

The OC4J-specific deployment descriptor configures the following:

  • Specify the Destination and connection factory JNDI locations to the MDB through the <message-driven-deployment> element in the orion-ejb-jar.xml file. See "Specify the Destination and Connection Factory" for full details.

  • Associate any logical names defined as resource references in the ejb-jar.xml file to the correct queue or topic, which, for Oracle JMS, was defined in the database through SQL. You could have several topics and queues defined in database. See "Map Any Resource References to JNDI Names" for full details on mapping the resource references in the orion-ejb-jar.xml file.


Since this example uses resource references in the ejb-jar.xml file, the orion-ejb-jar.xml file maps these logical names to the actual JNDI names of the connection factory and the JMS Destination object, which are defined in the database. In this example, the MDB uses a queue that is defined in the database as rpTestQueue. The queue connection factory is not defined in the database, so any name can be used. For consistency, the queue connection factory name is myQCF.

Specify the Destination and Connection Factory

Map the Destination and connection factory JNDI locations to the MDB through the <message-driven-deployment> element in the orion-ejb-jar.xml file. The following is the orion-ejb-jar.xml deployment descriptor for the rpTestMdb example. It maps a JMS Queue to the rpTestMdb MDB, providing the following:

  • MDB name, as defined in the <message-driven><ejb-name> in the EJB deployment descriptor, is specified in the name attribute.

  • JMS Destination Connection Factory, as specified by the user, is specified in the connection-factory-location attribute. The Oracle JMS syntax for the connection factory is "java:comp/resource" + JMS provider name + "TopicConnectionFactories" or "QueueConnectionFactories" + a user defined name. The user-defined name can be anything and does not match any other configuration. The xxxConnectionFactories details what type of factory is being defined. For this example, the JMS provider name is defined in the <resource-provider> element in the application.xml file as myProvider.

    • For a queue connection factory: Since the JMS provider name is myProvider and you decide to use a name of myQCF, the connection factory name is "java:comp/resource/myProvider/QueueConnectionFactories/myQCF".

    • For a topic connection factory: Since the JMS provider name is myProvider and you decide to use a name of myTCF, the connection factory name is "java:comp/resource/myProvider/TopicConnectionFactories/myTCF".

    The user defined names, as shown above by myQCF and myTCF, are not used for anything else in your logic. So, any name can be chosen.

  • JMS Destination, as defined in the database, is specified in the destination-location element. The Oracle JMS syntax for the Destination is "java:comp/resource" + JMS provider name + "Topics" or "Queues" + Destination name. The Topic or Queue details what type of Destination is being defined. The Destination name is the actual queue or topic name defined in the database.

    For this example, the JMS provider name is defined in the <resource-provider> element in the application.xml file as myProvider. In the database, the topic name is rpTestQueue.

    • For a queue: If the JMS provider name is myProvider and the queue name is rpTestQueue, then the JNDI name for the queue as "java:comp/resource/myProvider/Queues/rpTestQueue."

    • For a topic: If the JMS provider name is myProvider and the topic name is rpTestTopic, then the JNDI name for the topic as "java:comp/resource/myProvider/Topics/rpTestTopic."

  • If this was a topic, then a durable topic name, which is user-defined, is specified in the subscription-name attribute.

  • Listener threads are an optional parameter and defined in the listener-threads attribute. The listener threads are spawned off when MDBs are deployed and are used to listen for incoming JMS messages on the topic or queue. These threads concurrently consume JMS messages. The default is one thread. Topics always use only one thread; queues can use more than one.

  • Transaction timeout, as defined in the transaction-timeout attribute, is an optional parameter. This attribute controls the transaction timeout interval (in seconds) for any container-managed transactional MDB. The default is one day or 86,400 seconds. If the transaction has not completed in this time frame, the transaction is rolled back and the message is redelivered back to the Destination object.

    The MDB transaction-timeout attribute applies only to CMT MDBs that use Oracle JMS as the JMS provider. This attribute setting has no effect on BMT MDBs or any MDBs that use OC4J JMS:

    • JMS behavior with Oracle Application Server—JMS attempts to redeliver the message (defaults to five attempts and is set on the DBMS_AQADM.CREATE_QUEUE method when creating the queue in the database), after which the message is moved to the exception queue. You can browse messages in the exception queue using SQL*Plus. For more information on setting redelivery attempts and browsing the exception queue, refer to theOracle9i Application Developer's Guide—Advanced Queuing for Release 2 (9.2).

    • JMS behavior with OC4J—The transaction-timeout setting does not work for CMT MDBs that use OC4J JMS. The timeout is always one day and cannot be modified. When the timeout occurs, OC4J JMS redelivers the message indefinitely, until the delivery is successful. You cannot set a retry limit.

    In addition, the global transaction-timeout attribute defined in the server.xml file does not have any effect on MDBs.

Once all of these are specified in the <message-driven-deployment> element, the container knows how to map the MDB to the correct JMS Destination.

  <message-driven-deployment name="testMdb" 
     connection-factory-location=        "java:comp/resource/myProvider/QueueConnectionFactories/myQCF"
    destination-location="java:comp/resource/myProvider/Queues/rpTestQueue"
	listener-threads="5">

If you wanted to specify a topic, you must also include the subscription name, as follows:

<enterprise-beans>
  <message-driven-deployment 
      name="rpTestMdb" 
      connection-factory-location=
          "java:comp/resource/myProvider/TopicConnectionFactories/myTCF" 
      destination-location="java:comp/resource/cartojms1/Topics/rpTestTopic" 
      subscription-name="MDBSUB"
      listener-threads=1 >
  ...
</enterprise-beans>

Note:

You cannot use logical names in these fields. You must specify the full JNDI syntax for both the connection factory and the Destination object.

Map Any Resource References to JNDI Names

When you define logical names as resource references for your connection factory and Destination object, you have to map these to the actual JNDI names.

  • Map the resource reference for the queue connection factory in the <resource-ref-mapping> element. In the rpTestMdb example, the logical name for the connection factory is jms/myQueueConnectionFactory. This must be mapped to the JNDI string of java:comp/resource/myProvider/QueueConnectionFactories/myQCF.

  • Map the resource reference for the Destination object in the <resource-env-ref-mapping> element. In the rpTestMdb example, the logical name for the queue is jms/persistentQueue. This is mapped to the JNDI string of java:comp/resource/myProvider/Queues/rpTestQueue.

See "Specify the Destination and Connection Factory" for how the Oracle JMS JNDI syntax was derived.

<resource-ref-mapping name="jms/myQueueConnectionFactory"
       location="java:comp/resource/myProvider/QueueConnectionFactories/myQCF"/>
<resource-env-ref-mapping name="jms/persistentQueue"
       location="java:comp/resource/myProvider/Queues/rpTestQueue" />

Example 9-5 The orion-ejb-jar.xml file for the rpTestMdb Example

The following lists the complete orion-ejb-jar.xml file for the rpTestMdb example. It includes both the definition of the Oracle JMS objects and the resource reference mappings.

<enterprise-beans>
  <message-driven-deployment name="testMdb" 
     connection-factory-location=        "java:comp/resource/myProvider/QueueConnectionFactories/myQCF"
    destination-location="java:comp/resource/myProvider/Queues/rpTestQueue"
	listener-threads="5">

    <resource-ref-mapping name="jms/myQueueConnectionFactory"
       location="java:comp/resource/myProvider/QueueConnectionFactories/myQCF"/>
	    <resource-env-ref-mapping name="jms/persistentQueue"
       location="java:comp/resource/myProvider/Queues/rpTestQueue" />
  </message-driven-deployment>
</enterprise-beans>
<assembly-descriptor>
  <default-method-access>
    <security-role-mapping name="&lt;default-ejb-caller-role&gt;"
                           impliesAll="true" />
  </default-method-access>
</assembly-descriptor>

Deploy the MDB

Archive your MDB into a JAR file. You deploy the MDB in the same way as the session bean, which Prepare the EJB Application for Assembly and "Deploy the Enterprise Application to OC4J" describe.


Note:

Instructions on how a client sends a JMS message to the MDB is discussed in "Client Access of MDB".