I'll present you today the way to do custom xpath function in Oracle BPEL Process Manager 10.1.3.x. This stuff is very usefull for basic things (as an isNumber() method, ID generator, ...) or more complex things (as XML operations, business stuff).
I did many projects with Oracle BPM 10, and I've got used to use lots of those functions.
Step 1 - Make a class which implements the IXPathFunction interface
The next class is a little tool which tests if a string is a number.
Class IsNumberFunction :
package com.bpelsoa.xpath;
import java.util.List;
import org.w3c.dom.Node;
import com.collaxa.cube.xml.dom.DOMUtil;
import com.oracle.bpel.xml.xpath.IXPathContext;
import com.oracle.bpel.xml.xpath.IXPathFunction;
import com.oracle.bpel.xml.xpath.XPathFunctionException;
/**
* This implements a small tool which tests if a String is a Number.
*
* @author Raphaël
*
*/
public class IsNumberFunction implements IXPathFunction {
/** Number of args for this XPathFunction. */
private static final int NB_ARGS = 1;
/** Index in the List of our argument. */
private static final int INDEX_ARG = 0;
/**
* Is called by the BPEL engine.
*
* @see com.oracle.bpel.xml.xpath.IXPathFunction#call(com.oracle.bpel.xml.xpath
* .IXPathContext, java.util.List)
*/
@SuppressWarnings("unchecked")
public Object call(IXPathContext context, List args)
throws XPathFunctionException {
// test if we have the right argument number
if (args.size() != NB_ARGS) {
throw new XPathFunctionException(
"This function requires one argument.");
}
// extract the String of the argument from the BPEL process
Object o = args.get(INDEX_ARG);
String str = getValue(o);
// call the business method
return isNumber(str);
}
/**
* Extract the value of our String.
*
* @param o object
* @return a string which contains our value
* @throws XPathFunctionException if error occurs
*/
private String getValue(Object o) throws XPathFunctionException {
if (o instanceof String) {
return ((String) o);
} else if (o instanceof Node) {
return DOMUtil.getTextValue((Node) o);
} else {
throw new XPathFunctionException("Unknown argument type.");
}
}
/**
* Test if a String is a Number.
*
* @param str
* the String to be tested
* @return a boolean
*/
private boolean isNumber(String str) {
for (int i = 0; i < str.length(); i++) {
if (!Character.isDigit(str.charAt(i))) {
return Boolean.FALSE;
}
}
return Boolean.TRUE;
}
}
Step 2 - Register the xpath function to your BPEL domain
Edit the xpath-functions.xml file in the $BPEL_HOME/domains/bpelsoa/config directory.
Add these following lines into the bpel-xpath-functions tags.
<function id="isNumber">
<classname>com.bpelsoa.xpath.IsNumberFunction</classname>
<comment><![CDATA[This implements a small tool which tests if a String is a Number. The signature of this function is bpelsoa:isNumber(String || Node).]]></comment>
<property id="namespace-uri">
<value>http://bpelsoa.blogspot.com</value>
<comment>Namespace URI for this function</comment>
</property>
<property id="namespace-prefix">
<value>bpelsoa</value>
<comment>Namespace prefix for this function</comment>
</property>
</function>
Step 3 - Add your classfiles to the bpel classpath
Create a new directory in your domain home ($BPEL_HOME/domains/bpelsoa) called classes and add your classfiles into it or add your classfiles to your application directory (/product/your_app/classes). Don't forget to add the packages hierarchy.
Edit the shared library of your application server
- OC4J : $ORACLE_HOME/j2ee/oc4j_soa/config/server.xml
-> add a tag code-source with your classpath as the others code-source tags.
- WebSphere 6.1 : In the administration console, go to shared library, select the oracleBPELServer scope, and edit the orabpel_sl lib
Step 4 - Using your new custom xpath function in a BPEL process
A custom xpath function can be used as any xpath functions. It has to be in an expression field from an assign activity (copy, append, insert after/before, etc.).
<assign name="xpathCall">
<copy>
<from expression="bpelsoa:isNumber('123')"/>
<to variable="myBoolean"/>
</copy>
</assign>
Enjoy your new xpath.
That's all.