AOP and SOA/BPEL … with XSLT Transformation !

Strange combination isn’t it ? Well, it’s not so strange after all, when you think about adding automatic monitoring piece to your existing SOA/BPEL code. In Java language, we all know how AOP (with AspectJ ) helps Java developer to add cross-cutting concern in order to centralize for example some logging information. I wanted to used this principle but apply to my BPEL code. One can argue that Oracle SOA Suite already provide sensors for doing this; but we all know that this mandatory piece of information is often ignore due to time/project constraint.

The idea is pretty simple to implement. Let the BPEL developers build their BPEL process and focus on delivered the core business logic. Once this has been tested and validated; let use some XSLT transformation to automatically add sensors (could be composite sensor and external reference (EJB+JMS+WS); and/or activity sensor) and sensor actions to all the implemented BPEL process. This transformation can be called automatically during the build automation process (before compiling and packaging the BPEL Process with Maven for example).

I’m implementing this for a customer and it’s working pretty well.
For example; let suppose you have an XXX bpel process. You can use JDevelopper to create those files on a test project and analyze the generated XML code in order to build the adequate transformation:

  • For Composite Sensor: create a sensorAction.xml and sensor.xml file
  • For Activity Sensor: create a XXX_sensorAction.xml and XXX_sensor.xml file, where XXX is the name of your BPEL process
  • Update composite.xml to reference the generated sensor and sensorAction files

For example, here is a sample XSLT 2.0 transformation to implemented the last part. The others transformations are pretty easy to implement if you follow this convention : I have recursively parsed WSDL files inside the composite.xml to retrieve the attached operations (for JMS, EJB and Web Service)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

	<xsl:output method="xml" indent="yes" encoding="utf-8"/>

	<!-- Identity transform -->
	<xsl:template match="@* | node()">
		<xsl:copy>
			<xsl:apply-templates select="@* | node()" />
		</xsl:copy>
	</xsl:template>
		
	<xsl:template xmlns="http://xmlns.oracle.com/sca/1.0" xpath-default-namespace="http://xmlns.oracle.com/sca/1.0" match="composite/component[implementation.bpel]" >
		<xsl:copy>
			<xsl:apply-templates select="@*|node()" />
			<property  name="configuration.sensorLocation" type="xs:string" many="false"><xsl:value-of select="@name" />_sensor.xml</property>
			<property  name="configuration.sensorActionLocation" type="xs:string" many="false"><xsl:value-of select="@name" />_sensorAction.xml</property>
		</xsl:copy>		
	</xsl:template>	

	<xsl:template match="/" >
		<xsl:apply-templates />
	</xsl:template>

</xsl:stylesheet>  

Composite Sensor
** sample sensorAction.xml

.../...
<action name="JMSSensorAction_CompositeSensor_JMS_RCM_MDC_CONFIGURATION_Produce_Message" enabled="true" publishType="JMSQueue" publishTarget="jms/LinkyLogsQueue">
        <sensorName>CompositeSensor_JMS_RCM_MDC_CONFIGURATION_Produce_Message</sensorName>
        <property name="JMSConnectionFactory">jms/bpm/CaseEventConnectionFactory</property>
</action>  
.../...

** sample sensor.xml

.../...
<sensor sensorName="CompositeSensor_JMS_RCM_MDC_CONFIGURATION_Produce_Message" kind="reference" target="undefined" filter="">
        <referenceConfig reference="JMS_RCM_MDC_CONFIGURATION" expression="$in.property.tracking.ecid" operation="Produce_Message" outputDataType="string" outputNamespace="http://www.w3.org/2001/XMLSchema"/>
</sensor>
.../...  

ActivitySensor
** sample composite.xml

.../...
<component>
    <property name="configuration.sensorLocation" type="xs:string" many="false">SMC01_sensor.xml</property>
    <property name="configuration.sensorActionLocation" type="xs:string" many="false">SMC01_sensorAction.xml</property>
</component>
.../...

** XXX_sensorAction.xml

.../...
<actions targetNamespace="http://www.erdfdistribution.fr/linky/services/internes/bpel/smc01/v1" xmlns="http://xmlns.oracle.com/bpel/sensor" xmlns:tns="http://www.erdfdistribution.fr/linky/services/internes/bpel/smc01/v1" xmlns:pc="http://xmlns.oracle.com/bpel/sensor">
   <action name="SensorActionJMS" publishName="" publishType="JMSQueue" enabled="true" filter="" publishTarget="jms/LinkyLogsQueue">
      <property name="JMSConnectionFactory">jms/bpm/CaseEventConnectionFactory</property>
      <sensorName>ActivitySensor_receiveInput</sensorName>
   </action>
</actions>
.../...

** XXX_sensor.xml

.../...
<?xml version = '1.0' encoding = 'UTF-8'?>
<sensors targetNamespace="http://www.erdfdistribution.fr/linky/services/internes/bpel/smc01/v1" xmlns="http://xmlns.oracle.com/bpel/sensor" xmlns:tns="http://www.erdfdistribution.fr/linky/services/internes/bpel/smc01/v1" xmlns:pc="http://xmlns.oracle.com/bpel/sensor">
   <sensor sensorName="ActivitySensor_receiveInput" classname="oracle.tip.pc.services.reports.dca.agents.BpelActivitySensorAgent" kind="activity" target="receiveInput">
      <activityConfig evalTime="completion">
         <variable outputDataType="string" outputNamespace="http://www.w3.org/2001/XMLSchema" target="$Variable_ECID"/>
      </activityConfig>
   </sensor>
</sensors>
.../...

This can be extended to OSB project as well for proxy and business service; but creating a generic enough XSLT transformation could be tedious, as transformation is much more complex to implement, but this is do-able and a colleague is working on this part.

More to come …