How to Send JMS Messages to one Oracle Application Server while reading it from another.

Posted by Steve Racanovic | Posted in , | Posted on 2:01 PM

2

The example demonstrates a queue on one server (Server A), while having an MDB on another server (Server B) that listens to the queue. It also includes a client that connects to Server B and reads the messages.

The example involves having 2 Oracle Application Server. I'm using Oracle AS 10.1.3.2.0.

The following outline the tasks to be complete:
a) Server A is used to send the message to.
Need to create a JMS destination and queue connection factory
The queue on Server A will be called jms/MyJMSQueue.
The queue connection factory Server A will be called jms/MyJMSQCF.
The client will connect to server A and send a message to the queue.

b) Server B is used to read the messages.
Need to create a queue connection factory destination that point to Server A and the JMS destination as in Server A.
The queue on Server B is the same as Server A.
The queue connection factory Server B will be called jms/MyRemoteQCF.
The MDB will be deployed to Server B. The MDB will listen to messages on Server A.
The client will connect to server B and read messages from the queue.

1. On Server A, create a JMS Destination.

[sracanov@sracanov-au2 JMS_SR]$ cd $ORACLE_HOME\j2ee\JMS

[sracanov@sracanov-au2]$ java -jar admin_client.jar deployer:oc4j:opmn://sracanov-au2.au.oracle.com:6005/JMS_SR oc4jadmin welcome1 -addDestination -domain queue -name jmsqueue -jndiLocation jms/MyJMSQueue

2. On Server B, create a JMS Destination. Same as in step 1.

[sracanov@sracanov-au2]$ java -jar admin_client.jar deployer:oc4j:opmn://sracanov-au.au.oracle.com:6007/JMS oc4jadmin welcome1 -addDestination -domain queue -name jmsqueue -jndiLocation jms/MyJMSQueue

3. On Server A, create a Connection Factory.

[sracanov@sracanov-au2 JMS_SR]$ java -jar admin_client.jar deployer:oc4j:opmn:// sracanov-au2.au.oracle.com:6005/JMS_SR oc4jadmin welcome1 -addJMSConnectionFactory -domain queue -jndiLocation jms/MyJMSQCF

4. On Server B, create a Connection Factory.

First determine the jms port for the OC4J instance you are using on Server A.

[oracle@sracanov-au2 JMS_SR]$ opmnctl status -l


OC4JGroup:default_group | OC4J:JMS_SR | 11196 | Alive | 857355163 | 253252 | 23:27:49 | jms:12604,ajp:12504,rmis:12704,rmi:12404


The instance in the example is using port 12604.

On Server B, run the following:

[sracanov@sracanov-au D]$ java -jar admin_client.jar deployer:oc4j:opmn:// sracanov-au.au.oracle.com:6007/JMS oc4jadmin welcome1 -addJMSConnectionFactory -jndiLocation jms/MyRemoteQCF -domain queue -host sracanov-au2.au.oracle.com -username oc4jadmin -password welcome1 -port 12604

5. Create the QueueProducer.

Use the example code from the previous blog to create the QueueProducer class. The QueueProducer will connection to Server A and send messages to the queue. You will need to make the following changes to the class.


String queueName = "jms/MyJMSQueue";
String queueConnectionFactoryName = "jms/MyJMSQCF";

And

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, “oracle.j2ee.rmi.RMIInitialContextFactory");
env.put(Context.SECURITY_PRINCIPAL, "oc4jadmin");
env.put(Context.SECURITY_CREDENTIALS, "welcome1");
env.put(Context.PROVIDER_URL, "opmn:ormi://sracanov-au2.au.oracle.com:6005:JMS_SR/default");


Ensure you have set this to your Server A details, including opmn port, and oc4j instance.Use ‘opmnctl status –port’ to find your opmn port.

6) Run the QueueProducer class to send the message to the queue.

The is result:
Producing message: Message 1
Producing message: Message 2
Producing message: Message 3
Producing message: Message 4
Producing message: Message 5

7) From the Oracle EM, select your instance (in this example, ‘JMS_SR’) -> Administration -> JMS Destinations -> Memory Performance (on ‘jmsqueue’ in this example). Here you will see you messages in the queue.



8) Create the QueueConsumer.

Use the example code from the previous blog to create the QueueConsumer class. The QueueConsumer will connection to Server B and read messages from the queue on Server A. You will need to make the following changes to the class.


String queueName = "jms/MyJMSQueue";
String queueConnectionFactoryName = " jms/MyRemoteQCF";

And

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, “oracle.j2ee.rmi.RMIInitialContextFactory");
env.put(Context.SECURITY_PRINCIPAL, "oc4jadmin");
env.put(Context.SECURITY_CREDENTIALS, "welcome1");
env.put(Context.PROVIDER_URL, opmn:ormi:// sracanov-au.au.oracle.com:6007:JMS/default");


Ensure you have set this to your Server B details, including opmn port, and oc4j instance.

9) Now run the QueueConsumer class that will connect to Server B and receive the messages from the queue on Server A.

This is the result:

Consuming message: Message 1
Consuming message: Message 2
Consuming message: Message 3
Consuming message: Message 4
Consuming message: Message 5

10) Create an MBD and deploy to Server B that will listen and print the messages in the queue on Server A.

a.Create the MessageDrivenEJBBean as follows:


package project3;

import javax.ejb.EJBException;
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class MessageDrivenEJBBean implements MessageDrivenBean,
MessageListener {
private MessageDrivenContext _context;

public void ejbCreate() {
}

public void setMessageDrivenContext(MessageDrivenContext context) throws EJBException {
_context = context;
}

public void ejbRemove() throws EJBException {
}

public void onMessage(Message message) {
TextMessage msg = null;

try {
if (message instanceof TextMessage) {
msg = (TextMessage)message;
System.out.println("Reading message: " + msg.getText());
} else {
System.out.println("Wrong Message type");
}
} catch (JMSException e) {
System.out.println("JMSException in onMessage(): " + e.toString());
} catch (Throwable t) {
System.out.println("Exception in onMessage():" + t.getMessage());
}
}
}


b.Edit the ejb-jar.xml as follows:

<?xml version = '1.0' encoding = 'windows-1252'?>
<ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd" version="2.1"
xmlns="http://java.sun.com/xml/ns/j2ee">
<enterprise-beans>
<message-driven>
<description>Message Driven Bean</description>
<display-name>MessageDrivenEJB</display-name>
<ejb-name>MessageDrivenEJB</ejb-name>
<ejb-class>project3.MessageDrivenEJBBean</ejb-class>
<messaging-type>javax.jms.MessageListener</messaging-type>
<transaction-type>Container
<message-destination-type>javax.jms.Queue</message-destination-type>
<activation-config>
<activation-config-property>
<activation-config-property-name>destinationType</activation-config-property-name>
<activation-config-property-value>javax.jms.Queue</activation-config-property-value>
</activation-config-property>
<activation-config-property>
<activation-config-property-name>acknowledgeMode</activation-config-property-name>
<activation-config-property-value>Auto-acknowledge</activation-config-property-value>
</activation-config-property>
<activation-config-property>
<activation-config-property-name>subscriptionDurability</activation-config-property-name>
<activation-config-property-value>NonDurable</activation-config-property-value>
</activation-config-property>
</activation-config>
</message-driven>
</enterprise-beans>
</ejb-jar>

c.Edit the orion-ejb-jar.xml as follows:

<?xml version = '1.0' encoding = 'windows-1252'?>
<orion-ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/oracleas/schema/orion-ejb-jar-10_0.xsd"
schema-major-version="10" schema-minor-version="0">
<enterprise-beans>
<message-driven-deployment name="MessageDrivenEJB"
connection-factory-location="jms/MyRemoteQCF"
destination-location="jms/MyJMSQueue"/>
</enterprise-beans>
<assembly-descriptor>
<default-method-access>
<security-role-mapping/>
</default-method-access>
</assembly-descriptor>
</orion-ejb-jar>

d.Deploy MDB to Server B.

e.Run the QueueProduce to send some messages to the queue.

f.Open the file $ORACLE_HOME\opmn\log\default_group~~default_group~1.log

To view the result:

07/10/02 08:52:24 Reading message: Message 1
07/10/02 08:52:24 Reading message: Message 2
07/10/02 08:52:24 Reading message: Message 3
07/10/02 08:52:24 Reading message: Message 4
07/10/02 08:52:24 Reading message: Message 5
07/10/02 08:52:24 Wrong Message type

Comments (2)

thx for the info, it solved my prob
the annoying thing is its so implementation specific to oracle and ejb-jar.xml should be exactly like you have shown

oracle should have given jndi-bridge

Hi Steve, thanks for the blog post. Coincidentally, this is exactly what I'm doing (except that I'm implementing the MDB in EJB3.0 using Annotations).

It works fine (in general), except for a very strange (and intermittent) problem; that is sometimes the MDB just stops consuming the messages from the queue. The messages still stay on the queue in Server A. At those times I need to restart the OC4J on Server B and it works fine again. Have you encountered this before?

Just wondering whether the "remote queue connection factory" is an orthodox way to allow MDB to listen to a queue on a remote host. I searched and searched but couldn't find any documentations about this.