Oracle SOA, AIA BPEL ESB and OSB knowledge base

Monday, March 23, 2009

Dynamic transformations using Oracle Service Bus

Dynamic transformations using Oracle Service Bus

Thanks to Chris for making it very clear.

One of the new features in Oracle Service Bus 10gR3, and one commonly requested by customers, is the ability to choose the transformation to apply to a message based on runtime information - also known as dynamic transformations.

In the previous version of Oracle Service Bus you could only specify the transformation to be performed on the message at design time which may have resulted in:

- Multiple proxy services performing the same mediation logic, but applying different transformations

- A proxy service message flow containing a for loop with a number of cases each performing a different transformation

These scenarios can easily be handled when the number of transformations is small and/or doesn't change regularly but both scenarios involve modifying or creating a proxy service just to add a new transformation. Dynamic transformations allow you to define a proxy service which can handle new transformations being added at a later date.

Let's look at how we might implement a typical scenario where a proxy service accepts multiple versions of a message and applies an appropriate transformation based on the version of the message (determined by the namespace of the root element) in order to convert the message into a common format.

First create a new Oracle Service Bus project called DynamicTransformation (File>New>Oracle Service Bus Project, enter a name of DynamicTransformation and click Finish)

Then create a new schema file called Customer.xsd (File>New>Other>XML Schema) and define the common format with the target namespace http://www.oracle.com/Customer and the following structure:

customer_common_format

Now define a CustomerApplication business service which accepts messages in this format (File>New>Business Service, enter a name of CustomerApplication and click Finish)

Now in the main editor pane, select the General tab for this service and make sure it is defined as a Messaging Service.

Now move to the Messaging tab, set the Request Type to XML and click the Browse button to select the Customer element from Customer.xsd as the message format definition:

Now move to the Transport tab:

- Select the protocol as JMS

- Click Add to accept the default URL or modify it to point to a valid JMS endpoint

(NB. You will need to ensure the connection factory and queue specified in this JMS endpoint exist. If you accept the default, and are running on the default port of 7001 you should only need to create a JMS queue with a JNDI name of CustomerApplicationRequest on the WebLogic Server instance underpinning your Service Bus instance as the connection factory is created for you).

Now move to the JMS Transport tab:

- Select the Message Type as Text and leave the other values as their defaults.

Now test this business service is working as expected by right clicking on it in the Project Explorer and selecting Run As. When the Select Tasks dialog box appears, just click Finish. This should launch the Test Console.

Enter some sample data (the Test Console should have generated the structure for you) and then click Execute.

business_service_testing_customer_application

This should succeed but without a response (this is a one way service and the message has been placed on the CustomerApplicationRequest queue). Navigate to the CustomerApplicationJMS queue and check it contains your message:

customer_application_request

Next create a new schema file called CustomerV1.xsd and define the CustomerV1 format to be in the http://www.oracle.com/CustomerV1 target namespace and have the following structure:

customer_v1

And one called CustomerV2.xsd defining our CustomerV2 format to be in the http://www.oracle.com/CustomerV2 target namespace and have the following structure:

customer_v2

Next, lets create our transformations: Version1.xq (which converts from CustomerV1 format to the common Customer format):

Version1

And Version2.xq (which converts from Customer V2 format to the common Customer format):

Version2

NB. It is important the target namespaces and transformation filenames are named as described as this is how the correct transformation is selected.

So now we have our transformations and formats defined, the final step is to create our Customer proxy service (File>New>Proxy Service, enter name Customer and click Finish) which will actually perform the dynamic transformation.

In the General tab, select the Service Type to be Messaging Service.

In the Messaging tab, select the Request Type to be XML but don't specify a format (this is because this service can accept both V1 and V2 message formats).

In the Transport tab, select the Protocol to be JMS and accept the default endpoint (the queue and connection factory pointed at by this JMS endpoint will be created for you).

In the Message Flow tab create a message flow like the following which routes to the CustomerApplication business service:

dynamic_transformation_message_fllow

The Assign action extracts the version number (the last digit) from the namespace URI for the Customer element and stores it in the version variable:

assign_properties

NB. The XPath expression here gets the namespace URI of the Customer element (fn:namespace-uri), converts it into a string (fn:string) and then extracts the version number from the end of the string (fn:substring-after).

The Replace action replaces the entire contents of the body with the result of performing the XQuery transformation, the name of which is determined, in this case, by concatenating the static string DynamicTransformation/Version with the value stored in the version variable:

replace_properties

In order to create the Expression line you need to have clicked in the Expression field and completed the XQuery editor as follows:

xquery_expression_editor

The Bind Variables field defines the variable passed to the transformation. To create this simply enter the name Customer in the Add Custom Variable field and clicked Add. The XPath expression here evaluates to the Customer element within the body, irrespective of namespace.

After completing this, save everything and then launch the Test Console on the Customer proxy service (right click on it and select Run As).

Enter a CustomerV1 format message into the payload field (you can generate a sample one of these by right clicking on CustomerV1.xsd in Workshop and selecting Generate XML).

Then click Execute.

The invocation should succeed without a response - the V1 message should have been transformed to the common Customer format, the CustomerApplication business service invoked and a common Customer format message placed on the CustomerApplicationRequest JMS queue. Check the JMS queue to see this is the case.

Then try the same, but replace the payload with a CustomerV2 format message. This should also succeed without a response - the V2 message having been also transformed to the common Customer format and placed on the CustomerApplicationRequest JMS queue. Again, check the JMS queue to see that this is the case.

That's it. You've just implemented your first dynamic transformation with Oracle Service Bus - congratulations!

NB. A few words of caution when adopting an approach like the one described above. Since your proxy service now has a weakly defined service contract rather than a strongly defined one you will need to describe to your service consumers the message structure(s) your service supports (probably via documentation) and also ensure you have some error handling to deal with unsupported message formats.


8 comments:

Anonymous said...

Hi!

Can anyone tell me which is the Lookup-Table function of JDevelepor equivalent in OSB. I have an ESB Project that uses this function to get some valours from a table that then concatenates and I need to do the same in OSB.

Can you help me, please?

Thanks!

Abhishek Gupta said...

Hi,

OSB as of now doesn't have any lookup defined and portability with ESB. What you can do is either use database for same functionality or use BPEL to achieve same functionality.

Sorry to say that.

Anonymous said...

Hi!

I can access the database and retrieve data with an XQuery querie written in code transformation? Is it possible?

Thanks for your help!

Abhishek Gupta said...

If you get inbuilt function that gives you access to database, you can do it. But as of now better option is make java web service or BPEL web service and call as business service and get the value you want.

Mike Rdz said...

Hello,

Maybe this question might sound dumb for you guys who are really related with OSB and transformations, etc.

I'm working right now with the OSB and I have the requirement to map from a XML (based on a XSD that I use for the XQuery mapper tool) that will have multiple iterations for one tag...
The issue for me comes up when I need to map one of the iterations to the other XML, witch will have the same number of iterations, but mapped with some other name..

To be clear in one XML I'll have something like this

-?xml version="1.0" encoding="utf-8"?-
-mainTag-
-childTag-
-firstData-FirstOne-/firstData-
-secondData-SecondOne-/secondData-
-/childTag-
-childTag-
-firstData-FirstOne2ndRow-/firstData-
-secondData-SecondOne2ndRow-/secondData-
-childTag-
-firstData-FirstOne3rdRow-/firstData-
-secondData-SecondOne3rdRow-/secondData-
-/childTag-
-/mainTag-

And I need to map that information to another XML like
-?xml version="1.0" encoding="utf-8"?-
-myNewXML-
-thing row="1"-
-data-FirstOneAndSecondOne-/data-
-/thing-
-thing row="2"-
-data-FirstOne2ndRowAndSecondOne2ndRow-/data-
-/thing-
-thing row="3"-
-data-FirstOne3rdRowAndSecondOne3rdRow-/data-
-/thing-
-/myNewXML-

Hope the example helps.
I'm really new at this and I would love to learn how to speed up my knowledge on all this XML and XQuery mapping stuff.

I appreciate all your!

I'll be waiting on your answers!

Thanks and best regards!

Mike

Arun said...

Oracle Service Bus provides a database lookup function using a new XQuery function in the Oracle XQuery engine. This can be used for message enrichment, for routing decisions or for customizing the behavior of a proxy service. Read-access to databases from proxy services is supported without requiring writing of a custom EJB or custom Java code and without the need for a separate database product like Oracle Data Service Integrator.

Unknown said...

Hi,

I have a problem. not sure if somebody could help me. In my ESB project, there is a transformation. from the Source side, there are few changes in the schema. Client modifies and made editions to the Source WSDL.Now i would like to know , how do those changes in schema or new elements would get populated in the existing XSL, so that i can map those new elements and complete the requirement.
So say refresh would work.. BUt how to refresh, what to refresh? Can someone help me ple.

Thanks,Ravi.

Abhishek Gupta said...

Hi Vamshi,

You can open your project in JDeveloper and open your transformation.

Here you would see new element added in your schema (source/target)

Now map it accordingly save and redeploy.

Remember in 10g ESB modifying alone xsl is some time tedious because of cache. So i would recommend that you undeploy your ESB and clear your cache from server then deploy.

Hope this helps.

FEEDJIT Live Traffic Map

My Blog List