Oracle Service Bus, processing Java Object Messages with JMS transport

A few releases back Oracle enhanced to JMS transport to be able to handle Java Objects in queues and topic. The JMS transport now has the option to either receive Java Objects in the OSB processes by retrieving them from a topic or queue, or storing the plain Java Objects.

First we need to create a new queue in Weblogic, in my case QueueuIn.

1. Create the java entity object

Create the next entity object

package nl.xenta.entities;

import java.io.Serializable;

public class Employee  implements Serializable {
	
	private static final long serialVersionUID = -5802550970297576366L;
	public String firstname;
	public String lastname;
	public Integer age;
	
	public String getFirstname() {
		return firstname;
	}
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}
	public String getLastname() {
		return lastname;
	}
	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}

Build it and generate a jar file from it.

2. Client to send Java Object Message

package nl.xenta.utilities;

import java.util.Hashtable;

import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.InitialContext;

import nl.xenta.entities.Employee;
import nl.xenta.entities.Person;
import nl.xenta.services.EmployeeService;

public class JmsHelper {

	public final static String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory";
	public final static String JMS_FACTORY = "javax.jms.QueueConnectionFactory";
	public final static String QUEUE = "QueueIn";

	static QueueConnectionFactory factory;
	static QueueConnection qconnection;
	static QueueSession qsession;
	static QueueReceiver qreceiver;
	static Queue queue;
	static Context ctx;
	private boolean quit = false;

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void sendMessage() throws Exception {
		QueueConnection queueCon = null;
		try {
			// get the initial context, refer to your app server docs for this
			Hashtable<String, String> ht = new Hashtable<String, String>();
			ht.put(Context.INITIAL_CONTEXT_FACTORY,
					"weblogic.jndi.WLInitialContextFactory");
			ht.put(Context.PROVIDER_URL, "t3://localhost:7001");
			Context ctx = new InitialContext(ht);

			// get the connection factory, and open a connection
			QueueConnectionFactory qcf = (QueueConnectionFactory) ctx
					.lookup("weblogic/jms/XAConnectionFactory");
			queueCon = qcf.createQueueConnection();

			// create queue session off the connection
			QueueSession queueSession = queueCon.createQueueSession(false,
					Session.AUTO_ACKNOWLEDGE);

			// get handle on queue, create a sender and send the message
			Queue queue = (Queue) ctx.lookup(QUEUE);
			QueueSender sender = queueSession.createSender(queue);

			// create employee object
			Employee emp = new Employee();
			emp.setAge(32);
			emp.setFirstname("Eric");
			emp.setLastname("Elzinga");

			// send java object to queue
			Message msg = queueSession.createObjectMessage(emp);
			sender.send(msg);

			System.out.println("Send Java Object Message");
		} finally {
			// close the queue connection
			if (queueCon != null) {
				queueCon.close();
			}
		}
	}
}

Execute the jms java client to create Employee object and store it on the QueueIn queue.
Go to the Weblogic Console to see if the message arrived in the QueueIn queue.

When we now click on the message it will give the next message

	Unable to view message, reason = java.lang.ClassNotFoundException: nl.xenta.entities.Employee

Copy the builded jar from step1 (the jar with the compiled Employee class in it) to the next location

	YOUR_MIDDLEWARE_HOME/user_projects/domains/osb_domain/lib

Restart Weblogic and try viewing the message in the console again.

Great, it worked. Now we can see a Employee object is stored in the queue.
Let’s go on with the OSB part.

3. Oracle Service Bus Proxy Service

  1. First copy the jar created in step 2 to our OSB project.
  2. Create a new Messaging Proxy Service
  3. Select ‘Java’ for Request Message Type
  4. Use jms protocol and configure the endpoint (use the just created queue)

    Select Queue for Destination Type

    Configure the Client Jar and browse to the jar file generated in step 2.

    If we skip this settings the proxyservice won’t be able to deserialize the java objects retrieved from the queue. Resulting in stacktraces like this

    ####<Aug 28, 2011 10:23:56 AM CEST> <Error> <OSB Kernel> <multimedia> <AdminServer> <[ACTIVE] ExecuteThread: '26' for queue: 'weblogic.kernel.Default (self-tuning)'> <<anonymous>> <BEA1-03E7A5A49D452A912D4B> <1bf9ba3a756c6ce8:6b05e983:1320f4d10ed:-8000-00000000000000bb> <1314519836078> <BEA-380003> <Exception on TransportManagerImpl.receiveMessage, com.bea.wli.sb.context.BindingLayerException: General runtime error: [JMSClientExceptions:055115]Error deserializing an object
    com.bea.wli.sb.context.BindingLayerException: General runtime error: [JMSClientExceptions:055115]Error deserializing an object
    
    Caused By: java.lang.ClassNotFoundException: nl.xenta.entities.Employee
    	at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    
  5. Create the Message Flow as defined in the picture and only add a log activity, which logs the body.

Deploy the process and use the JmsHelper client to create an Employee object and send it to the queue.
The proxy service will poll, get it out of the queue and basically does nothing with it except logging the body.
After the message is send, check the osb domain log file to see what’s in the $body variable.

<BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, stage2, REQUEST] ### debug logging $body ###: <soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <con:java-content ref="jcid:4c741db6:131dd1e4544:-7fc5" xmlns:con="http://www.bea.com/wli/sb/context"/>
</soapenv:Body>> 

The java object is retrieved from the queue and processed by the proxy service.
But when we look in the body we don’t see any ‘actual’ payload, only a java ref to the java object itself.

Let’s use a few java callouts to see how we can use the content of the java object.

4. Proxyservice, java callout, java (object) in, string out

Extend the java project from step1.
Create a new class (EmployeeService) with the next method (convertEmployeeToString) in it

package nl.xenta.services;

import java.io.File;
import java.io.IOException;

import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;

import nl.xenta.crm.employee.EmployeeDocument;
import nl.xenta.crm.employee.EmployeeType;
import nl.xenta.entities.Employee;
import nl.xenta.entities.Person;

public class EmployeeService {

	public static String convertEmployeeToString(Employee employee) {
		return employee.toString();
	}
}

The input Employee object will be the data from the queue and as response we just return the string value of the object.
Generate a jar archive from it and store it in your OSB project.

Add the java callout to your proxy service message flow and after it add the log activity.
The log activity will just log the value of $my_string_response.

Now trigger the process again by sending a message with the JmsHelper client and check the osb log file.

<BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, stage2, REQUEST] ### JMSObject_ps, logging string response after the java callout ###: Employee [firstname=Eric, lastname=Elzinga, age=32]> 

Read this for some extra information about the java callouts and their input and return types.
“The input and return types for Java callouts are not restricted. However, any return types other than primitives, Strings, or XmlObjects can only be passed (unmodified) to other Java callouts.”
In this example we get a String returned, so we can just retrieve the value of it in the message flow without sending it to another java callout.

5. Proxyservice, java (object) in, java (object) out

For this example i made a copy of the Employee object and named it Person. We will use the same Employee object as example1 for the input and return a Person object back to OSB and log this.

	public static Person convertEmployeeToPerson(Employee employee) {
		Person person = new Person();
		
		person.setFirstname(employee.firstname);
		person.setLastname(employee.lastname);
		person.setAge(employee.age);
		
		return person;
	}

<BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, stage2, REQUEST] ### JMSObject_ps, logging person response after the java callout ###: <con:java-content ref="jcid:4cd600ef:131e1eeb1b1:-7fca" xmlns:con="http://www.bea.com/wli/sb/context"/>> 

And again we get a java ref back, only this time a new ref id to a new object.
To be able to ‘use’ this object we can either send it to a new java callout or publish it to another queue.

6. Proxyservice, java (object) in, XmlObject out

See this blog on how to send the java object to a java callout and return a XmlObject back.
I added the XMLBeans resources (build.xml and libs) to the same project as mentioned in step1.

For this testcase we used the next method. It will receive the Employee object from the queue and return the xml(object) representation of it back to the OSB.

	public static XmlObject convertJavaToXml(Employee employee) throws Exception {
		EmployeeDocument empDoc = EmployeeDocument.Factory.newInstance();
		EmployeeType myEmp = empDoc.addNewEmployee();
		myEmp.setAge(32);
		myEmp.setFirstName("Eric");
		myEmp.setLastName("Elzinga");
			
		return myEmp;			
	}

Run the ant build script again and copy the jar to our OSB project.
In this jar we will find the Employee and Person entities, the generated XMLBeans artifacts and the static methods used for the java callout. I guess we could have splitted some of those in other archives, but for the simplicity of this article it’s fine like this.
The jar we used in the other cases won’t be needed anymore since all we need is in this new one.

Don’t forget to edit the proxyservice and change the Client Jar to the new jar.

And the java callout

<BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, stage2, REQUEST] ### JMSObject_ps, logging my_employee_xml response after the java callout ###: <emp:employee xmlns:emp="http://xenta.nl/crm/employee">
  <emp:FirstName>Eric</emp:FirstName>
  <emp:LastName>Elzinga</emp:LastName>
  <emp:Age>32</emp:Age>
</emp:employee>> 

With this final testcase we’re able to retrieve the java object from the queue, convert it to a xml representation and send it back to the proxy service.
In the message flow we’re now able to retrieve data from it by use of some xpath expression.

Share this Post:
Digg Google Bookmarks reddit Mixx StumbleUpon Technorati Yahoo! Buzz DesignFloat Delicious BlinkList Furl

2 Responses to “Oracle Service Bus, processing Java Object Messages with JMS transport”

[...] Oracle Service Bus, processing Java Object Messages with JMS transport | Oracle .. Java .. OpenSourc… | January 11th, 2012 at 12:59 pm [...]

Leave a Reply:

Name (required):
Mail (will not be published) (required):
Website:
Comment (required):
XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>