Creating a custom XPath function for SOA Suite

In this recipe, we will create a custom XPath function in java that can be used by any composite component in an assign or transform. This enables us to add complex logic into our XPath expressions without making an explicit call to Java. We will use the example of calculating the mean and standard deviation of a set of numbers.

Getting ready

Our XPath function will have a signature, as shown in the following code snippet:

double getStdDev(values as node-set)

It will take the value of each node in the input node set, calculate it, and return the standard deviation.

How to do it...

  1. Create a project with the appropriate libraries that are required by XPath.

    In JDeveloper create a new Java project. From the new projects Project Properties, choose the Libraries and Classpath tab and choose Add Library to add the SOA Runtime library and the Oracle XML Parser v2 library to the project. Click on OK until the Project Properties dialog closes.

    How to do it...
  2. Create a new Java Class in the project and add a static method to the class that takes an oracle.xml.parser.v2.XMLNodeList as the input parameter (this is the input to our function) and returns a java.lang.Double (the output of our function). The method name is the name of our XPath function.
    How to do it...

    This is the method that we will use to provide the implementation of our custom XPath function. It is also the method we will register with the XSLT engine.

    A sample class is shown as follows:

    package soa.cookbook.xpath;
    
    import oracle.xml.parser.v2.XMLNodeList;
    
    public class StdDev {
      public static double getStdDev(XMLNodeList nodes)
      {
        return null;
      }
    }
  3. Access the input values.

    The input parameter to our XPath function is a list of nodes that we can iterate over through each node:

    for (int i = 0; i < nodes.getLength(); i++) {
      try {
        Node node = nodes.item(i);

    We can then check that the node is of the expected type; in our case we expect an element:

    if (node.getNodeType() == Node.ELEMENT_NODE) {
  4. Get the input value.

    We can then access the value of the element as a string and parse it into the double we expect:

    double value = Double.parseDouble(node.getTextContent());

    We wrap the parameter processing in a try-catch block so that we can ignore any unexpected data types.

      }
    } catch (Exception e) {
      ; // Ignore non-numeric values
    }

    We can now manipulate the data passed in to our function.

  5. Add the required libraries.

    Our implementation makes use of the Apache Commons Math library, and so we need to add that library to our Project Properties by going to the Libraries and Classpath tab and choosing Add Library. We can then click the New button to add a new library to JDeveloper.

    How to do it...

    On the Create Library dialog, we can specify a name for the library and then choose the Class Path and click Add Entry to bring up the Select Path Entry dialog, which will allow us to choose the JAR file or classpath that we need to add to find the classes in the library.

    How to do it...

    We can then specify the Source Path and Doc Path if those are also available for the library. Finally, we add the library by clicking on OK and then select the library from the Add Library dialog to include it in our project.

  6. Implement the function logic.

    To implement the function logic, we begin by executing the initialization code before we start iterating over the nodes in the XMLNodeList .

    DescriptiveStatistics stats = new DescriptiveStatistics();
    
    for (int i = 0; i < nodes.getLength(); i++) {
    
    
    
    XMLNodeList nodes = (XMLNodeList)list.get(0);

    Within the iteration of XMLNodeList, we then add the value of the element to the statistics we are gathering.

    double value = Double.parseDouble(node.getTextContent());
    stats.addValue(value);
    

    Finally, we return the standard deviation as the result of the XPath function by passing it out as the return value of the method.

    return stats.getStandardDeviation();
  7. Create a BPEL and Mediator wrapper function.

    BPEL and Mediator components can use custom XPath functions, but they have a slightly different interface than custom XSLT XPath functions, so we will now implement that interface—oracle.fabric.common.xml.xpath.IXPathFunction .

    We modify our class to implement the interface by right-clicking on the class name and choosing Source | Implement Interface. We then use the Hierarchy browser in the Implement Interface dialog to select the IXPathFunction interface.

    How to do it...

    This creates a new method in our class:

    public Object call(IXPathContext iXPathContext,
                       List list) throws XPathFunctionException {
      return null;
    }

    The call method takes an IXPathContext and a List as the input parameters and returns an Object. The method should declare that it throws an XPathFunctionException .

  8. Get a single parameter.

    The input parameters to the XPath function are available in the list parameter of our method.

    We have only one parameter, so we can access it by getting the first item in the list and casting it to the expected type, an XMLNodeList:

    NodeList nodes = (NodeList)list.get(0);

    The iXPathContext provides access to the calling component (Mediator and BPEL) and to any variables declared in that component.

    We need to pass the function input parameters to the static method we previously implemented, so we'll just call that method from the new method:

    return getStdDev(nodes);
    How to do it...
  9. Create the custom XPath descriptor file.

    To tell both JDeveloper and SOA Suite about our custom XPath functions, we must create their description in an XML file. The file is called ext-soa-xpath-functions-config.xml and must be created in the project's src/META-INF directory.

    This file must have the following content:

    <?xml version="1.0" encoding="UTF-8"?>
    <soa-xpath-functions
      xmlns="http://xmlns.oracle.com/soa/config/xpath"
      xmlns:stat=
    "http://www.oracle.com/XSL/Transform/java/soa.cookbook.xpath.StdDev" >
    

    The soa-xpath-functions element is in the http://xmlns.oracle.com/soa/config/xpath namespace and must specify a target namespace prefix (with a name of our choosing) that references a namespace made up of two parts. The first part of the namespace must be http://www.oracle.com/XSL/Transform/java/ and the final part must be the canonical class name of the class implementing the static XSLT function, called soa.cookbook.xpath.StdDev.

  10. Define the XPath function name.

    The function name element is used to register the name of the function. The function name is used by XSLT to identify the static method in the class that was previously identified.

    <function name="stat:getStdDev">
  11. Identify the function implementation class.

    The className element identifies the class that implements the BPEL and Mediator call method.

        <className>soa.cookbook.xpath.StdDev</className>
    
  12. Define the XPath function's return type.

    The return element identifies the return type of the function.

        <return type="number"/>
    
  13. Define the XPath function's parameters.

    The params element lists the parameters of the function, identifying their names and types.

        <params>
          <param name="data" type="node-set"/>
        </params>
    
  14. Provide the XPath function's description.

    The desc element provides the function summary that will appear in the brief description in JDeveloper.

        <desc>Returns the Standard Deviation of the values of the
              input node-set</desc>
    

    The detail element provides the detailed description that appears in JDeveloper.

        <detail>Returns the Standard Deviation of the values of
                the top level elements in the node-set passed as
                a parameter. </detail>
      </function>
    </soa-xpath-functions>
  15. Packaging the XPath functions in a JAR file.

    Having created the descriptor file, we now package the XPath function into a JAR file by going to Project Properties and selecting the Deployment tab. Here, we create a New deployment that will be used to package the XPath function we have created.

    How to do it...

    In the Create Deployment Profile dialog, we give the profile a name and choose it to be of the type JAR File, and then click on OK.

  16. Add additional libraries to Deployment Profile.

    In the Edit JAR Deployment Profile Properties dialog, we go to the Contributors section of the Project Output section in File Properties and click on the Add button to add a new contributor. Here, in the Add Contributor dialog, we enter the path for any libraries that need to be included in our custom XPath library; in our case we add the Apache Math library.

    How to do it...
  17. Generate the JAR file.
    How to do it...

    Having created the profile, we can now deploy it by right-clicking on the project and selecting Deploy to generate our JAR file.

  18. Register the XPath functions with JDeveloper.

    To use the custom function in JDeveloper, we must go to Tools | Preferences and choose the SOA section.

    Clicking on Add allows us to locate our newly created JAR file in the deploy directory of our project and register it with JDeveloper.

    How to do it...
  19. Register the XPath functions with SOA Suite.

    To use our custom XPath functions in an SOA Suite installation, we need to copy the generated JAR file to $ORA LE_HOME/soa/modules/oracle.soa.ext_11.1.1.

  20. Use the XPath functions.
    How to do it...

We can use our custom XPath function just like any other XPath function by choosing it from Component Palette. It will be listed under the User Defined section.

How it works...

When we register our XPath JAR file with JDeveloper and SOA Suite, they look in the META-INF directory for a configuration file that will tell them what functions are being registered and which classes implement those functions. The name of the configuration file varies according to which component types we want to allow to access our XPath function. The format of the file is the same for all the components; the name of the file and the component types they apply to are shown in the following table:

Filename

Registered Component

XSLT

BPEL

Mediator

Human Workflow

ext-soa-xpath-functions-config.xml

Yes

Yes

Yes

Yes

ext-mapper-xpath-functions-config.xml

Yes

No

No

No

ext-bpel-xpath-functions-config.xml

No

Yes

No

No

ext-mediator-xpath-functions-config.xml

No

No

Yes

No

ext-wf-xpath-functions-config.xml

No

No

No

Yes

If we do not wish to register our function with the XSLT mapper, because for instance it made use of the name of the currently active composite or component, we would need to provide three identical files to register with BPEL (ext-bpel-xpath-functions-config.xml), Mediator (ext-mediator-xpath-functions-config.xml), and Human Workflow (ext-wf-xpath-functions-config.xml).

When our function is called from XSLT, the parameters to the function map directly onto the parameters of our static method. The parameter mappings from the XSD type in our XPath function to the Java type in our static method are shown as follows:

XPath Function Parameter Type (XSD)

Java Method Parameter Type

String

java.lang.String

Boolean

boolean or java.lang.Boolean

Number

int or java.lang.Integer or float or java.lang.Float or double or java.lang.Double

node-set

oracle.xml.parser.v2.XMLNodeList

tree

oracle.xml.parser.v2.XMLDocumentFragment

A node set will have multiple XML elements at the same level and is useful for when we want to operate across multiple elements; in our example, we used it to pass multiple values for statistical analysis. A tree has a single, top-level XML element that will usually have a number of nested XML elements.

When our function is called from BPEL, Mediator, or Human Workflow, the list of parameters are packaged up into a java.util.List and passed as a single parameter to our registered class' call method.

There's more...

If we have more than one parameter, we can iterate over the list using a for statement:

For (Object o : list) {
  ...
}

The IXPathContext parameter for the XPath functions registered with BPEL and Mediator is used to pass information about the calling component. In particular, it can be used to determine the type and name of the calling component, and provides access to any variables in that component.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.41.148