Caveat
For a better understanding of the details used herein please refer to the
How-To on OTN.
Requirements
You need an Oracle Database that supports AQ configuration. Also
OC4J/Oracle Application Server 10.1.3.3 or later is required. I've tested this with
OC4J 10.1.3.3 standalone and
SOA Suite 10.1.3.1 patched to 10.1.3.3. Tests with OC4J 10.1.3.2 showed some issues.
The Application
In JDeveloper create a new application called AQ. Don't create a new project (simply cancel that window). This application will eventually contain two projects for the AQ configuration and a remote client test project.
The Resource Adapter
Create a new empty project named
AQRA for AQ Resource Adapter. In this project create two new deployment descriptors:
ra.xml and
oc4j-ra.xml. Finally create a RAR deployment profile named
aqjms to package the resource adapter. We can use the deployment profile as it was created.
ra.xml
After JDeveloper has created the default file content for the
ra.xml we replace the whole content with the one from the
ra.xml that comes with the How-to (see References). You can either remove or keep the comments. Now comes the tricky part: We need to have good, easier to type names. Therfore we replace the
OEMSJMSDReference with
aqRP. Secondly the
<adminobject>'s that have the
jndiName Queues/MY_QUEUE or
Topics/MY_TOPIC should be removed. The generic approach for accessing the queues is good enough for us.
oc4j-ra.xml
We do the same as with the
ra.xml with the
oc4j-ra.xml file, ie replacing the whole content of the file with the content of the sample
oc4j-ra.xml from the How-to. The tricky part is the same here, we need to have good, easier to type names:
- Replace connector-name="OEMSJMSDRAInstanceName" with connector-name="AQRA"
- Likewise we change the location="OEMSJMSDRASubcontext to location="AQJMSSubcontext
Deployment Profile
We can use the RAR deployment profile as created by JDeveloper. Doing a
Recompile All will move the deployment descriptors to classes directory and makes them visible for the profile.
The Enterprise Application
Once we have done the resource adapter, we need to package it properly as a Java EE Enterprise Application in an
EAR file. For this we create a
new empty project called
EAR. In this project we need to create
three OC4J-specific deployment descriptors:
data-sources.xml,
orion-application.xml, and
oc4j-connectors.xml. Next, we create an EAR deployment profile called
aqear for the final EAR creation.
data-sources.xml
The data-sources.xml contains just the configuration needed for the AQ data source. Nothing more. Here is the complete file:
<?xml version = '1.0' encoding = 'windows-1252'?>
<data-sources xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/oracleas/schema/data-sources-10_1.xsd">
<managed-data-source connection-pool-name="aqPool" jndi-name="jdbc/aqDS"
name="aqDS"/>
<connection-pool name="aqPool">
<connection-factory factory-class="oracle.jdbc.pool.OracleDataSource"
user="jmsuser" password="welcome1"
url="jdbc:oracle:thin:@//localhost:1521/XE">
<proxy-interface sql-object="PreparedStatement"
interface="oracle.jdbc.OraclePreparedStatement"/>
<proxy-interface sql-object="Connection"
interface="oracle.jdbc.internal.OracleConnection"/>
<proxy-interface sql-object="CallableStatement"
interface="oracle.jdbc.OracleCallableStatement"/>
<proxy-interface sql-object="Statement"
interface="oracle.jdbc.OracleStatement"/>
<proxy-interface sql-object="ResultSet"
interface="oracle.jdbc.OracleResultSet"/>
</connection-factory>
</connection-pool>
</data-sources>
orion-application.xml
In the
orion-application.xml we configure the link between the data source and the resource adapter, the
<resource-provider> tag. Here is the complete file:
<?xml version = '1.0' encoding = 'windows-1252'?>
<orion-application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/oracleas/schema/orion-application-10_0.xsd">
<data-sources path="./data-sources.xml" />
<connectors path="./oc4j-connectors.xml" />
<resource-provider class="oracle.jms.OjmsContext" name="aqRP">
<property name="datasource" value="jdbc/aqDS" />
</resource-provider>
</orion-application>
oc4j-connectors.xml
The next file is the
oc4j-connectors.xml. In this file we configure the link between the resource provider and the JNDI space. Here is the complete file:
<?xml version="1.0" encoding="windows-1252" ?>
<oc4j-connectors xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.oracle.com/technology/oracleas/schema/oc4j-connectors-10_0.xsd"
schema-major-version="10" schema-minor-version="0">
<connector name="AQRA" path="aqjms.rar">
<config-property name="lookupMethod" value="resourceProvider" />
<config-property name="resourceProviderName" value="aqRP" />
<adminobject-config location="aq/Queues">
<adminobject-class>oracle.j2ee.ra.jms.generic.AdminObjectQueueImpl</adminobject-class>
<config-property name="resourceProviderName" value="aqRP" />
</adminobject-config>
<adminobject-config location="aq/Topics">
<adminobject-class>oracle.j2ee.ra.jms.generic.AdminObjectTopicImpl</adminobject-class>
<config-property name="resourceProviderName" value="aqRP" />
</adminobject-config>
</connector>
</oc4j-connectors>
EAR deployment profile
By default the EAR deployment profile includes the standard deployment descriptors. To add the
oc4j-connectors.xml we need some extra steps. Double click on the deployment profile and create a new file group (I called it
files). In the
Filters sub item select
only the
oc4j-connectors.xml to be included. The rest will be included automagically.

The AQ Setup
To setup the AQ Queues and Topics you should use a SQL script. This comes in handy to redo it when needed (eg. when moving from Development to Production). Here is a simple script:
BEGIN
DBMS_AQADM.CREATE_QUEUE_TABLE(
queue_table => 'FromTable',
queue_payload_type => 'SYS.AQ$_JMS_MESSAGE',
sort_list => 'PRIORITY,ENQ_TIME',
multiple_consumers => false,
compatible => '9.2');
DBMS_AQADM.CREATE_QUEUE(
queue_name => 'FROM_QUEUE',
queue_table => 'FromTable');
DBMS_AQADM.START_QUEUE(
queue_name => 'FROM_QUEUE');
DBMS_AQADM.CREATE_QUEUE_TABLE(
Queue_table => 'ToTable',
Queue_payload_type => 'SYS.AQ$_JMS_MESSAGE',
sort_list => 'PRIORITY,ENQ_TIME',
multiple_consumers => false,
compatible => '9.2');
DBMS_AQADM.CREATE_QUEUE(
Queue_name => 'TO_QUEUE',
Queue_table => 'ToTable');
DBMS_AQADM.START_QUEUE(
queue_name => 'TO_QUEUE');
DBMS_AQADM.CREATE_QUEUE_TABLE(
Queue_table => 'LOGQTABLE',
Queue_payload_type => 'SYS.AQ$_JMS_MESSAGE',
sort_list => 'PRIORITY,ENQ_TIME',
multiple_consumers => false,
compatible => '9.2');
DBMS_AQADM.CREATE_QUEUE(
Queue_name => 'logQ',
Queue_table => 'LOGQTABLE',
max_retries => '2');
DBMS_AQADM.START_QUEUE(
queue_name => 'logQ');
END;
The Remote Client
Finally, we create an empty project called
client for the remote test client. As it is always useful to test your configuration, this one can always be used for configuration verification and sanity checks. It both sends and receives from the queues. For brevity I'll show the sending part only. The receiving part is left as an exercise to the reader.
System.out.println("Testing queue using " + factoryName + ' ' +
destinationName);
Connection conn = null;
Session sess = null;
MessageProducer prod = null;
boolean verbose = false;
try {
ConnectionFactory factory = (ConnectionFactory)ctx.lookup(factoryName);
Destination destSend = (Destination)ctx.lookup(destinationName);
conn = factory.createConnection();
conn.start();
sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
prod = sess.createProducer(destSend);
TextMessage payload = sess.createTextMessage();
payload.setText(msg);
payload.setJMSCorrelationID(new Long(System.currentTimeMillis()).toString());
prod.send(payload);
System.out.print("Send " + payload.getJMSCorrelationID());
if (verbose) {
System.out.print(' ' + payload.getText());
}
System.out.println();
} finally {
closeJMSResources(prod, sess, conn);
prod = null;
sess = null;
conn = null;
}As good developer we use the
jndi.properties file for configuring the JNDI connection and credentials setup.
Needed Libraries
The remote client needs a number of libraries to work properly. These are (within JDeveloper 10.1.3.3):
- J2EE
- Oracle 9 iAS
- $OC4J_HOME/j2ee/home/lib/javax77.jar
- $OC4J_HOME/j2ee/home/lib/jmxri.jar
- $OC4J_HOME/j2ee/home/lib/connector.jar
- $OC4J_HOME/j2ee/home/lib/adminclient.jar
- $OC4J_HOME/j2ee/home/lib/bcel.jar
- $OC4J_HOME/j2ee/home/jazncore.jar
- Oracle JDBC
What JNDI names should I use then?
The JNDI names you should use are:
- AQJMSsubcontext/My{CF,QCF,TCF,XACF,XAQCF,XATCF}
- aq/Queues/Queues/<queue_name> or aq/Topics/Topics/<topic_name>
Global Setup
For a server global setup of the AQ resource adapter, you can deploy the RAR file directly from the
aqjms deployment profile to OC4J. The only downside is that you have to do the configuration of the global configuration files
application.xml,
data-sources.xml, and
oc4j-connectors.xml manually.
References
Comments (2)
It is great blog. I wonder if I can have the complete set of files which contains the testing clients.
Thanks
Posted by Mark | August 29, 2008 5:57 PM
Posted on August 29, 2008 17:57
Olaf,
Thanks a again for your blog.
By following the step and step instructions above, I got everything work and the teating client (servlet) is able to send and receive messages from the AQ (Queue name: FROM_QUEUE) defined.
Now I am trying to test with using MDB 3.0. Somehow the message driven bean is never fired up. Do I need any additional configurations to make MDB work? If so, please give your suggestions. The testing MDB code is below, please let me know if I miss anything:
package mdb;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.Message;
import javax.jms.TextMessage;
import javax.jms.MessageListener;
import oracle.j2ee.ejb.MessageDrivenDeployment;
@MessageDriven(
messageListenerInterface=MessageListener.class,
activationConfig = {
@ActivationConfigProperty(
propertyName="connectionFactoryJndiName", propertyValue="AQJMSSubcontext/MyQCF"),
@ActivationConfigProperty(
propertyName="destinationName", propertyValue="aq/Queues/Queues/FROM_QUEUE"),
@ActivationConfigProperty(
propertyName="destinationType", propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(
propertyName="messageSelector", propertyValue="RECIPIENT = 'MDB'")
})
//@MessageDrivenDeployment(resourceAdapter = "AQRA")
public class QueueMDBBean implements MessageListener {
public void onMessage(Message msg) {
System.out.println("mdb is invoked." + msg);
}
}
Posted by Mark | August 31, 2008 6:04 AM
Posted on August 31, 2008 06:04