LinkedIn

Friday, May 20, 2011

Integrating Oracle BAM 11g with BPEL JMS Sensor Action

First of all I am blogging about this thing because i recently had a requirement in one of my work to create variable sensors in my BPEL project that can be used to create real time reporting dashboards in BAM.

Seems quite an easy task in Oracle SOA Suite 11g as we can create a BAM Adapter in our composite and create a sensor action to post data to BAM ADC data objects. This blog by Lucas Jellema perfectly explains this

http://technology.amis.nl/blog/3098/integrating-bpel-and-bam-in-oracle-11g-soa-suite

However this was ruled out because we had a PUB SUB scenario and hence we wanted to create a JMS sensor action to  publish data to a Weblogic JMS topic and use BAM Enterprise Messaging Source to create and populate BAM data objects.
BAM Architect allows us to setup Enterprise Message Sources that can be used to link BAM Data Objects with JMS Topics or Queues. In such an Enterprise Message Source definition, we indicate such a JMS source of messages and specify how to transform the contents of the JMS messages into BAM Data Objects. Message queuing on a JMS queue is more or less a standard operation in many tools and technologies and gives us a means to have various technologies send their data (events) to Oracle BAM 11g.

Prerequisites
  • SOA Suite 11gPS2 or PS3 is installed in your local machine.
  • A SOA Domain that has BAM capabilities (either an all in one or standard) is created in your local machine.
  • JDeveloper is installed in your local machine.
  • An Oracle Database (11g preferably) is accessible from the SOA domain.

The Scenario Explained

We will be creating a very simple Order Creation Process in Oracle BPEL that takes a Sales Order Request. The BPEL process has a variable sensor that pushes sensor data to a JMS Queue.

We would then create a BAM Data object with key indicators we would need to monitor.

Using BAM Architect view we define a BAM Enterprise Message Source to create a hook to this queue, flatter the JMS sensor message to extract only the required indicators and transform the flattened message to map it to the data object we created.

Not that complex.

The Solution

Create an composite with BPEL Project in JDeveloper. While creating the BPEL project base it on the SalesOrder schema given below

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:sal="http://beatechnologies.wordpress.com/bpel/sensor" targetNamespace="http://beatechnologies.wordpress.com/bpel/sensor" elementFormDefault="qualified">
<xs:element name="CreateSalesOrder">
<xs:complexType>
<xs:sequence>
<xs:element name="OrderID" type="xs:string"/>
<xs:element name="OrderDate" type="xs:dateTime"/>
<xs:element name="CustomerID" type="xs:string"/>
<xs:element name="ContactID" type="xs:string"/>
<xs:element name="SalesPerson" type="xs:string"/>
<xs:element name="OrderAllowance" type="sal:SalesOrderAllowance"/>
<xs:element name="OrderCharges" type="sal:SalesOrderCharges"/>
<xs:element name="OrderStatus" type="xs:string"/>
<xs:element name="OrderAmount" type="xs:string"/>
<xs:element name="OrderItem" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="OrderID" type="xs:string"/>
<xs:element name="ModelId" type="xs:string"/>
<xs:element name="Quantity" type="xs:string"/>
<xs:element name="Price" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="PromisedShipDateTime" type="xs:dateTime"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="CreateSalesOrderResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="orderBookingStatus" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="SalesOrderAllowance">
<xs:sequence>
<xs:element name="OrderDiscount" type="xs:string"/>
<xs:element name="QuantityDiscount" type="xs:string"/>
<xs:element name="CustomerDiscount" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="SalesOrderCharges">
<xs:sequence>
<xs:element name="Tax" type="xs:string"/>
<xs:element name="Excise" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

image

Similarly choose the Output type as CreateSalesOrderResponse.

image

Drag an Assign Action between the receiveSalesOrder and End salesOrderResponse and assign a dummy status to the output variable.

image

Click on the Monitor button in the BPEL pane to be able to add Sensor information for the process.

This will open up the BPEL Structure view where we can add monitors/sensors and sensor actions. If this view doent open up then Click on View->Structure to see this.

Under Sensors right click on Variable and click Create. This opens up a pop up to create variable sensor for the bpel process. Create a sensor as shown under.

image

Now we have to define a sensor Action. Basically we have created a sensor to publish the whole incoming message to the queue. You can selectively use your desired part in the XML.

Before creating a sensor Action go to the Admin console of your SOA domain and create a Connection Factory and Queue in the SOAJMSModule. Target them to the SOASubDeployment on the SOAJMSServer for the purpose of this demonstration.

image

Now in the Create Variable Sensor pop up define a sensor action as shown below

image

Now deploy this process to the soa_server1 Managed server and use either the EM console or any Web service Testing tool to invoke this process with a sample request.

I use the following request to invoke my process
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sen="http://beatechnologies.wordpress.com/bpel/sensor">
<soapenv:Header/>
<soapenv:Body>
<sen:CreateSalesOrder>
<sen:OrderID>200100102</sen:OrderID>
<sen:OrderDate>2011-05-18T09:36:12</sen:OrderDate>
<sen:CustomerID>5001020</sen:CustomerID>
<sen:ContactID>161921021</sen:ContactID>
<sen:SalesPerson>Arun Pareek</sen:SalesPerson>
<sen:OrderAllowance>
<sen:OrderDiscount>4200</sen:OrderDiscount>
<sen:QuantityDiscount>200</sen:QuantityDiscount>
<sen:CustomerDiscount>100</sen:CustomerDiscount>
</sen:OrderAllowance>
<sen:OrderCharges>
<sen:Tax>300</sen:Tax>
<sen:Excise>200</sen:Excise>
</sen:OrderCharges>
<sen:OrderStatus>Create</sen:OrderStatus>
<sen:OrderAmount>18900</sen:OrderAmount>
<sen:OrderItem>
<sen:OrderID>1</sen:OrderID>
<sen:ModelId>1728192</sen:ModelId>
<sen:Quantity>2</sen:Quantity>
<sen:Price>6000</sen:Price>
</sen:OrderItem>
<sen:OrderItem>
<sen:OrderID>2</sen:OrderID>
<sen:ModelId>1728193</sen:ModelId>
<sen:Quantity>2</sen:Quantity>
<sen:Price>6000</sen:Price>
</sen:OrderItem>
<sen:OrderItem>
<sen:OrderID>3</sen:OrderID>
<sen:ModelId>1728198</sen:ModelId>
<sen:Quantity>4</sen:Quantity>
<sen:Price>6900</sen:Price>
</sen:OrderItem>
<sen:PromisedShipDateTime>2011-05-23T09:36:12</sen:PromisedShipDateTime>
</sen:CreateSalesOrder>
</soapenv:Body>
</soapenv:Envelope>

image

You can also see that the sensor data now lies in the JMS queue that we configured

image

Well now we are all good with the BPEL part. All that we have to do is create a Data Object in BAM Architect view and then an EMS source to consume the message from this queue and populate the BAM data object.

Open up BAM Architect View.

Create a folder named Order. Now create a Data Object under this folder called SalesOrder as under

image

Create this data Object. Now Select Enterprise Message Sources from the BAM Architect console and click on create to create a new EMS.

image

The first part of the configuration is rather simple. We have to give the Server JNDI, Queue name and Connection Factory name in the appropriate places to let this EMS link to our Queue.

JMS Message Type should be Text as this is the type selected while publishing the message to the queue.

Select the SalesOrder data object under Order folder for the Data Object Name field selection.

Specify the other settings as seen above.

Now the other part of configuring the EMS is involved in mapping the message in the queue to the Data Object variables.

For this what i feel appropriate is to flatten the Queue XML message to a rather simple XML message i.e remove all element hierarchies.

Under XML Formatting click on Pre Processing and then on Advanced Formatting options to open an XSLT editor.

Use the following XSLT to flatten the sensor data in the queue to a simple OrderInformationMetric xml fragment

<xsl:stylesheet xmlns:sal="http://beatechnologies.wordpress.com/bpel/sensor" xmlns:tns="http://xmlns.oracle.com/bpel/sensor" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xsl sal xsd tns">
<xsl:template match="/">
<sal:OrderInformationMetric>
<sal:salesOrderID>
<xsl:value-of select="/tns:actionData/tns:payload/tns:variableData/tns:data/sal:CreateSalesOrder/sal:OrderID"/>
</sal:salesOrderID>
<sal:orderDate>
<xsl:value-of select="/tns:actionData/tns:payload/tns:variableData/tns:data/sal:CreateSalesOrder/sal:OrderDate"/>
</sal:orderDate>
<sal:customerNumber>
<xsl:value-of select="/tns:actionData/tns:payload/tns:variableData/tns:data/sal:CreateSalesOrder/sal:CustomerID"/>
</sal:customerNumber>
<sal:discount>
<xsl:value-of select="sum(/tns:actionData/tns:payload/tns:variableData/tns:data/sal:CreateSalesOrder/sal:OrderAllowance/*)"/>
</sal:discount>
<sal:orderTotal>
<xsl:value-of select="sum(/tns:actionData/tns:payload/tns:variableData/tns:data/sal:CreateSalesOrder/sal:OrderCharges/*)+
/tns:actionData/tns:payload/tns:variableData/tns:data/sal:CreateSalesOrder/sal:OrderAmount"/>
</sal:orderTotal>
<sal:orderLines>
<xsl:value-of select="count(/tns:actionData/tns:payload/tns:variableData/tns:data/sal:CreateSalesOrder/sal:OrderItem)"/>
</sal:orderLines>
<sal:promisedShipDate>
<xsl:value-of select="/tns:actionData/tns:payload/tns:variableData/tns:data/sal:CreateSalesOrder/sal:PromisedShipDateTime"/>
</sal:promisedShipDate>
</sal:OrderInformationMetric>
</xsl:template>
</xsl:stylesheet>

image

You can also verify and test your XSLT against the Sensor message.

Here is a the output of the XSLT transformation.

<sal:OrderInformationMetric xmlns:sal="http://beatechnologies.wordpress.com/bpel/sensor">
<sal:salesOrderID>200100102</sal:salesOrderID>
<sal:orderDate>2011-05-18T09:36:12</sal:orderDate>
<sal:customerNumber>5001020</sal:customerNumber>
<sal:discount>4500</sal:discount>
<sal:orderTotal>19400</sal:orderTotal>
<sal:orderLines>3</sal:orderLines>
<sal:promisedShipDate>2011-05-23T09:36:12</sal:promisedShipDate>
</sal:OrderInformationMetric>

The rest is pretty simple. Follow the screen shot below

image

Here Message Element Name should be the root element of the Transformed Message. Also give the correct namespace under the Namespace URI field.

Under Source to Data Object Field Mapping add all the fields in the Data Object one by one and in the  Tag/Attr name column simply assign the element name in the transformed message whose data you wish to map to the data object field. Save the EMS configuration.

The last thing would be to Start the EMS so that it can listen to the configured Queue.  After the status of the EMS is Started’ click on Metrics’.

The count of Total Message Received will now be shown as 1.

image

Now go to the Data Objects view in the BAM Architect and Sales Order data object. The Row Count is shown as 1. Click on Contents to see the data object content. This contains the sensor values for the sales order.

image

Well that's it. Now go ahead and create BAM dashboard/reports from the gathered data in the BAM active cache.

Try invoking the service again with more requests and see how the cache content refreshes.

Important Note

In case you need to create an EMS that can handle message batches configure the EMS with Batching enabled and specify the Message Batching Element [This will essentially be the repeating node in the XML]

1 comment:

  1. Just desire to say your article is as surprising. The clarity in your post is simply excellent and i can assume you're an expert on this subject. Well with your permission allow me to grab your RSS feed to keep updated with forthcoming post. Thanks a million and please keep up the enjoyable work.

    ReplyDelete