Wednesday, June 2, 2010

SOASuite 11g- Implement User-Defined XPath Extension Functions

I had previously written a blog on creating XPATH function in 10g. This write up is on how to achieve the same in 11g.

In 11g the major difference is that XPATH functions has been extended to some more components.

· BPEL

· Mediator

· Human workflow

· XSLT Mapper

The implementation is different only for XSLT mapping. For all other components implementation is same. Functions can be shared across all components and is defined by the xpath-functions-config xml file.

For each component we will define functions in a component specific config file

BPEL - ext-bpel-xpath-functions-config.xml

Mediator - ext-mediator-xpath-functions-config.xml

XSLT Mapper - ext-mapper-xpath-functions-config.xml

Common to all - ext-soa-xpath-functions-config.xml

I will explain the steps involved to create user-defined Xpath function for both BPEL and XSL mapper.

BPEL

For creating user-defined XPATH function, we need to define a java component and a xml component .The Xml component will take care of the configuration where as java component will be the implementation of the function.

We will start with xml component. We will define the function interface in a xml format.

1. Create an xml file - ext-bpel-xpath-functions-config.xml

Add this xml snippet

<soa-xpath-functions version="11.1.1"

xmlns="http://xmlns.oracle.com/soa/config/xpath"

xmlns:geo="http://www.geo-functions.com/HelloWorld">

<function name="geo:helloWorld">

<className>com.geo.xpath.HelloWorldTest</className>

<return type="string"/>

<params>

<param name="value" type="string"/>

</params>

<desc/>

<detail>

<![CDATA[This function returns a HelloWorld message.]]>

</detail>

</function>

</soa-xpath-functions>

here function signature is helloWorld() ,The namespace of the function is xmlns:geo=http://www.geo-functions.com/HelloWorld

2. Create a simple java class to implement the XPATH BPEL function.

The java class should implement oracle.fabric.common.xml.xpath.IXPathFunction interface. You can find this class and related xpath functions in fabric-runtime.jar


Code Snippet HelloWorldTest.java

package com.geo.xpath;

import oracle.fabric.common.xml.xpath.IXPathFunction;

import oracle.fabric.common.xml.xpath.IXPathContext;

import oracle.fabric.common.xml.xpath.XPathFunctionException;

import java.util.List;

public class HelloWorldTest implements IXPathFunction {

public Object call(IXPathContext context, List args) throws XPathFunctionException {

return "Hello world :: "+args.get(0);

}

}

You need to have fabric-runtime.jar in your classpath for compiling this java class.

>javac -classpath lib\ fabric-runtime.jar -d classes com\geo\xpath\HelloWorldTest.java

Here lib points to the location of these jars. –d classes points to the output folder where I will get my class file.

3. Create a jar with the generated class file.

>jar -cvf helloWorld.jar com/geo/xpath/HelloWorldTest.class

The jar will not be complete without the configuration file. Now add the ext-bpel-xpath-functions-config.xml file to the META-INF folder

Development of custom XPATH function is done. Now we will use it.

Usage

In the BPEL process use an assign operation to invoke the function

Code Snippet of .bpel file

<assign name="Assign_1">

<copy>

<from expression="geo:helloWorld(string(bpws:getVariableData('inputVariable','payload','/client:process/client:input')))"/>

<to variable="Invoke_1_execute_InputVariable" part="request"

query="/ns3:singleString/ns3:input"/>

</copy>

</assign>

When you compile the bpel process you will get a compilation error because the namespace-prefix and namespace-uri are not declared in the bpel process. Add the namespace- prefix and namespace-uri from your new function defined in ext-bpel-xpath-functions-config.xml to the process tag of .bpel file

Code Snippet of .bpel file

<process name="XpathBpel" targetNamespace="http://xmlns.oracle.com/XpathBpel"

……….

……. xmlns:geo="http://www.geo-functions.com/HelloWorld"

>

Compile and deploy your bpel process. The output will be the return string of the call method defined in the function.

Runtime usage:

1. Copy the HelloWorld function jar to MIDDLEWARE_Home/user_projects/domains/soa_domain/lib or a subdirectory of lib.

2. Restart the Oracle WebLogic Server.

XSLT Mapper

As we did for BPEL, we need to define a java component and a xml component .The Xml component will take care of the configuration where as java component will be the implementation of the function.

We will start with xml component. We will define the function interface in an xml format.

1. Create an xml file - ext-mapper-xpath-functions-config.xml

Add this xml snippet

<soa-xpath-functions version="11.1.1"

xmlns="http://xmlns.oracle.com/soa/config/xpath"

xmlns:geo="http://www.oracle.com/XSL/Transform/java/com.geo.xpath.HelloWorldXSLTest">

<function name="geo:helloWorldXSL">

<className>com.geo.xpath.HelloWorldXSLTest</className>

<return type="string"/>

<params>

<param name="value" type="string"/>

</params>

<desc/>

<detail>

<![CDATA[This function returns a HelloWorld message.]]>

</detail>

</function>

</soa-xpath-functions>

Here function signature is helloWorldXSL() ,The namespace of the function is xmlns:geo= http://www.oracle.com/XSL/Transform/java/com.geo.xpath.HelloWorldXSLTest". The difference with BPEL XPATH function is the namespace. Here the namespace should be in a specific format. http://www.oracle.com/XSL/Transform/java/ + package name +Class name

2. Create a simple java class to implement the XPATH BPEL function. A point to note is that for each function you need to write a corresponding public static method. The function name and method name must match.


Code Snippet HelloWorldXSLTest.java

package com.geo.xpath;

public class HelloWorldXSLTest {

public static String helloWorldXSL(String input){

return "Hello worldXSL :: "+input;

}

}

Compile this java class.

>javac -d classes com\geo\xpath\HelloWorldXSLTest.java

3. Create a jar with the generated class file.

>jar -cvf helloWorldXSL.jar com/geo/xpath/HelloWorldXSLTest.class

The jar will not be complete without the configuration file. Now add the ext-mapper-xpath-functions-config.xml file to the META-INF folder

Development of custom XSL Mapper XPATH function is done. Now we will use it.

Usage

JDeveloper will support user defined XSL functions .To use it from the wizard

· In Oracle JDeveloper, go to Tools > Preferences > SOA.

· Click the Add button and select your JAR file.

· Restart Oracle JDeveloper for the changes to take effect.

The function will be listed in the user-defined functions under Component Palette. You can directly drag and drop into your XSL.

Code Snippet of .xsl file

<xsl:stylesheet version="1.0"

xmlns:geo="http://www.oracle.com/XSL/Transform/java/com.geo.xpath.HelloWorldXSLTest"

…………

…………..

>

<xsl:template match="/">

<client:processResponse>

<client:result>

<xsl:value-of select="geo:helloWorldXSL(/client:process/client:input)"/>

</client:result>

</client:processResponse>

</xsl:template>

</xsl:stylesheet>

Compile and deploy your bpel/mediator process having your XSL mapping file. The output will be the return string of the method defined in the function.

Runtime usage:

1. Copy the HelloWorldXSL function jar to MIDDLEWARE_Home/user_projects/domains/soa_domain/lib or a subdirectory of lib.

2. Restart the Oracle WebLogic Server.

That’s it J

24 comments:

Unknown said...

The Custom XPATH function never works... Did you unit tested once.?

Unknown said...

Xpaths always works. We have used custom xpath functions in 10g as well as 11g projects. Let me know the issue so I can help.

Unknown said...

Hey I am sorry,I found the problem. It is working.. It is my bad.. Sorry again..

Anonymous said...

Hi,

I am working with custom Xpath function in jdeveloper. I am creating ext-mapper-xpath-functions-config.xml file. I have followed the developers guide and your blog also. I have done whatever mentioned here. Created the jar file with the xml file and class file. And added the jar file to the Jdeveloper. But I am not able to see the User defined functions part in the Components palette. Can u help me..?
Thanks,

Unknown said...

Once you upload the Jar into the Jdeveloper, open an XSL file.In component palette select User Defined option from drop down menu.There you will see a sub menu User Defined Extension Functions under which you will see all your custom made extension functions.

Anonymous said...

In componenet palette I am not able to see the User Defined Functions option itself. Do we have to do any other configurations other than browsing the Jar file in SOA.

Unknown said...

Just make sure you are using the component palette with XSL file opened in the main window.
Then User Defined Extension Functions & User Defined Named Templates options should be visible.
I am using 11.1.1.2 version. Its there for me.

Shyam said...

Hi George,

Great post. Your explanation is very lucid. What we are implementing using XPath functions can be implemented by calling an external jar from a Java Embed activity. So how is using XPath Extension functions advantageous?

Regards,
Shyam

Unknown said...

The idea of writing functions is to re-use the functionality in different places instead of replicating the code in multiple processes using java embedding.The second advantage is that the implementation is hidden from the user, so in future if the business logic of function changes we can update the xpath function without affecting the bpel or business process flows.

Anonymous said...

Have you tried with functions with repeated parameters (maxOccurs="unbounded")?

Ho to define this kind of parameters in the java file? I have tried String[] and List type without success.

How do you solved optional parameters (minOccurs="0")?

How to create define the parameter in the java file here?

Rohan said...

Hi Gearge,
I have created the jar file with all the java classes required. Can you tell where to upload this jar file in 11g runtime environment?

Unknown said...

Runtime usage:

1. Copy the HelloWorld function jar to MIDDLEWARE_Home/user_projects/domains/soa_domain/lib or a subdirectory of lib.

Krishna Chaitanya said...

Hi George,

i tried to execute the bpel process with custom xpath and got the below error..

An error occurs while processing the XPath expression; the expression is geo:helloWorld(string(bpws:getVariableData('inputVariable','payload','/client:process/client:input'))).
The XPath expression failed to execute; the reason was: Extension function namespace should start with 'http://www.oracle.com/XSL/Transform/java/'..

should I change the namespace reference of 'geo' to http://www.oracle.com/XSL/Transform/java?

Unknown said...

Couple of things u want to make sure is that u r using ext-bpel-xpath-functions-config.xml. for custom xpaths.

The namespace 'http://www.oracle.com/XSL/Transform/java/ is appended to the class name in case we use it in XSLT transform ,and not in XPAth in an assign activity.
The approach has not changed from 10g to 11g, except that the config file names have changed, and there is option to use same custom xpath functions across different components.

Mahesh Upadhyay said...

George,

I have followed your instructions, I can see user defined functions. after deploying I get below error:

The following exception occurred while attempting to execute operation copy at line 198

-

XML Parsing Error: junk after document element
Location: http://127.0.0.1:7001/em/ai/sca/share/audit/nfdg/displayInstance.jsp?locatorobjkey=Farm_SOADEVSOADEVsoa_serversoa-infra&instanceid=bpel%3A10003
Line Number 7, Column 1:



javax.xml.transform.TransformerException: oramds:/deployed-composites/default/TEST_rev1.0/xsl/Transformation_3.xsl<Line 20, Column 98>: XML-22043: (Error) Extension function error: Method not found &apos;paddingString&apos;oracle.xml.xpath.JXPathExpression.evaluate#242com.collaxa.cube.xml.xpath.BPELXPathUtil.evaluate#240com.collaxa.cube.engine.ext.bpel.common.BPELWMPHelper.evalFromValue#339com.collaxa.cube.engine.ext.bpel.v1.wmp.BPEL1AssignWMP.__executeStatements#137com.collaxa.cube.engine.ext.bpel.common.wmp.BaseBPELActivityWMP.perform#158com.collaxa.cube.engine.CubeEngine.performActivity#2543com.collaxa.cube.engine.CubeEngine._handleWorkItem#1165com.collaxa.cube.engine.CubeEngine.handleWorkItem#1071com.collaxa.cube.engine.dispatch.message.instance.PerformMessageHandler.handleLocal#73com.collaxa.cube.engine.dispatch.DispatchHelper.handleLocalMessage#220com.collaxa.cube.engine.dispatch.DispatchHelper.sendMemory#328com.collaxa.cube.engine.CubeEngine.endRequest#4430com.collaxa.cube.engine.CubeEngine.endRequest#4361com.collaxa.cube.engine.CubeEngine._createAndInvoke#698com.collaxa.cube.engine.CubeEngine.createAndInvoke#555com.collaxa.cube.engine.delivery.DeliveryService.handleInvoke#673...
^

Unknown said...

Mahesh,
u will need to provide more information.You need tocheck whether you created the proper config file for defining the function specific for XSL. In case you have defined for Xpath it will not work for XSL. So if you can provide the steps we can check.

Anonymous said...

Hi George,
I am able to see the user defined functions and it works for me on jdeveloper xslt mapper.But when I am placing the same jar in my domain lib,its not working.Am I doing some wrong here? Infact the user difined function being executed but the args are not being passed from xslt mapping.
Thanx-Aswini

Stuart said...

Have you been able to get this working in XSLT on 11.1.1.6?

We have taken your sample and tested it in BPEL and Mediator and BPM (using an assign) it works fine but does not work in an XSLT (tried BPEL and BPM).

We are trying to understand if this is version issue or something else.
Regards
Stuart

Unknown said...

Stuart,
I dont think it will be a version issue, as it will be the common approach followed for 11g series.
It may have something to do with config file.I have not tried with BPM,but bpel it should work.

Unknown said...

Hi,

Can you tell me how this can be done with BPM???

I have to call a simple java class from Oracle BPM 11g process w/o making any service calls.

TIA...

Unknown said...

Hi George,

Is there any differences between Custom Xpath functions 11g and 12c ? if so please provide the information.

Unknown said...

Hi George Thomas,

Not Sure whether you are active on this section or not. I hope you are so that our queries will be answered !

George, I am a Java resource and have not much idea about FCM, SOA thing. I am working for my client and we are facing one error which we are unable to resolve. I provide her Web-Service(War) and she tests at FCM and while testing we receive below error. Pl: We do not have enough resource to look at this issue. Any help will be appreciated.


An error occurs while processing the XPath expression; the expression is ora:doXSLTransformForDoc('xsl/STEP1FCMInputToIntegrationInput.xsl',$GetStepParams_OutputVariable.parameters

Hoping for your favorable response.

Thanks,
Kailash

Unknown said...

it has to do with your xpath in transformation. try using a sample payload to test the transformation.

Unknown said...

Thanks George. Issue got resolved after changing XSLT and code. Below was the comment we received from Oracle Team.

The error happened during transformation step, which transform of the variable $GetStepParams_OutputVariable.parameters Using XSLT string in the file xsl/STEP1FCMInputToIntegrationInput.xsl.

My suggestion is to check the audit trail to get the value of the variable $GetStepParams_OutputVariable.parameters and also check the XSLT string in the file xsl/STEP1FCMInputToIntegrationInput.xsl to see why transformation failed. If client has access to JDeveloper, they could use JDeveloper to quickly test the XSLT string, and figure out what is the correct syntax.

Thanks,
Kailash