Copy of Deconstructing the Inverse Functions Sample This page last changed on Dec 31, 2008. ## Examining the Inverse Functions Sample This topic describes how to define and configure inverse functions using the sample dataspace and Java function library as an example.
| For more information about the inverse functions sample, see Exploring the Inverse Functions Sample.
#### Topic Map Examining the Inverse Functions Sample Overview Creating the Underlying Java Functions Creating the Physical Data Services Based on the Functions Configuring the Inverse Functions Create the Data Service Related Topics Using Inverse Functions to Improve Query Performance ### Overview You need to complete the following actions to use inverse functions: Create the underlying Java functions Create physical data services based on the functions Add comparison logic to the data service Configure the inverse functions Create the data service ### Creating the Underlying Java Functions The inverse functions sample includes logic to perform transformations between: first/last names and full names department names and numbers employee IDs and names The string manipulation logic to manipulate first and last names needed by the inverse function is in the following Java file in the `JavaFunctionLib` project:
    JavaFunctionLib/JavaFuncs/NameLib.java
This file defines three string manipulation functions.
    package JavaFuncs;

    public class NameLib
    {
       public static String fullname(String fn, String ln) {
          return (fn == null || ln == null) ? null : (fn + " " + ln);
       }

       public static String firstname(String name) {
          try {
             int sepidx = name.indexOf(' ');
             if (sepidx < 0) return null;
               return name.substring(0, sepidx);
          }
          catch (Exception e) { return null; }
       }

       public static String lastname(String name) {
          try {
             int sepidx = name.indexOf(' ');
             if (sepidx < 0) return null;
                return name.substring(sepidx+1, name.length());
          }
          catch (Exception e) { return null; }
       }

       public static void main(String[] args) {
          String first = "John";
          String last  = "Doe";
          String full  = "John Doe";
          System.out.println(fullname(first, last));
          System.out.println(firstname(full));
          System.out.println(lastname(full));
          System.out.println(firstname(first));
          System.out.println(lastname(first));
       }
    }
Notice that the function `fullname()` simply concatenates the first and last names. In contrast, the `firstnname()` and `lastname()` functions deconstruct the resulting full name using the required space in the full name string as the marker identifying the separation between first and last names. Or, put another way, the `fullname()` function is the invertible of `firstname()` and `lastname()`. Similar functions are available in the `DeptLib` and `EmpIdLib` packages supporting transformations between department names and numbers, and employee IDs and names respectively. ### Creating the Physical Data Services Based on the Functions After you have compiled the Java functions, you can create a physical data service from the resulting class file. In the sample, physical data services were created using the `NameLib.class`, `DeptLib.class`, and `EmpIdLib.class` files.
| See Create a Physical Data Service from a Java Function for step-by-step instructions for creating a physical data service from a class file.
In the sample, the resulting operations corresponding to the string manipulation logic reside in the `NameFunc.ds` data service, as illustrated by the following: ##### NameFunc.ds Data Service #### Adding Comparison Logic to the Data Service As is often the case, some additional programming logic is needed. In the case of the sample, a function, `fullnameEQ()`, compares names and returns a Boolean value indicating whether the names are identical.
    declare function f1:fullnameEQ($full1 as xs:string?, $full2 as xs:string?) as xs:boolean? {
      (f1:firstname($full1)eq f1:firstname($full2)) and (f1:lastname($full1) eq f1:lastname($full2))
    };
| You can define additional functions for specific conditions, such as "is greater-than" or "is-less-than." Later, when configuring the inverse functions, you can create associations for these conditionals enabling the the XQuery engine to substitute the custom logic for a simple conditional.
| Associating Custom Conditional Logic with Functions
### Configuring the Inverse Functions You need to configure the inverse functions to perform the reverse transformation of the data. In this particular case, this means that you need to identify an inverse function for each parameter in the `fullname()` function.
| Inverse functions can only be defined when the input and output function parameters are atomic types.
To association the parameters of a function with inverse functions: Double-click on the data service in Project Explorer. For example, double-click `NameFuncs.ds` in the sample. Right-click on the function with which you want to associate inverse functions, and choose Configure Inverse Function. In the sample, right-click the `fullname` operation and choose Configure Inverse Function. ##### Selecting Configure Inverse Function A dialog appears enabling you to select the inverse functions for each parameter. Choose the corresponding inverse functions for each parameter using the drop-down lists, and click Next. ##### Selecting Configure Inverse Function Specify the equivalent transforms. Associating Custom Conditional Logic with Functions After you have associated inverse functions with the correct parameters, you may want to associate custom conditional logic with the functions. You do this by substituting a custom function for such generic conditions as eq (is equal to) and gt (is greater than). The following table lists conditional operations available for such transformations.
Conditional Operation | Definition
--- | ---
gt | string-greater-than
ne | string-not-equal
lt | string-less-than
ge | string-greater-than-or-equal-to
eq | string-equal
le | string-less-than-or-equal-to
Associating a particular conditional (such as "is greater-than") with a transformational function allows the XQuery engine to substitute the custom logic for a simple conditional. As is always the case with Oracle Data Service Integrator, the original basis of the function does not matter. It could be created in your data service, or externally in a Java or other routine. In this example the transformational function, `fullnameEQ`, is in the Java-based physical data service. Defining the Equivalent Transforms ### Create the Data Service The final step is to build the data service that contains the operations to create, read, update, and delete the data. In the sample dataspace, this data service, `Employee.ds`, includes operations such as `createEmployee`, `getAll`, `updateEmployee`, and `deleteEmployee`. The data service also includes operations such as `getByDeptName`, `getByEmpName`, and `getByEmpNo`. The following shows the overview of the `Employee.ds` data service. Employee.ds Data Service The data service uses XML types associated with the `Employee.xsd` schema. This schema could have been created through the XQuery Editor, through the Oracle Data Service Integrator schema editor, or through a third-party editing tool. The `getAll()` operation returns all employee records, as shown in the following listing:
    declare function ns1:getAll() as element(ns1:Employee)* {
       for $EMP2 in emp2:EMP2()
       return
          <tns:Employee>
             <EmpNo>{emp1:empnum($EMP2/EmpId)}</EmpNo>
             <EmpName?>{nam:fullname($EMP2/FirstName, $EMP2/LastName)}</EmpName>
             <MgrName?>{fn:data($EMP2/MgrName)}</MgrName>
             <Dept?>{dep:deptname($EMP2/Dept)}</Dept>
          </tns:Employee>
    };
Examining the query plan for the `getAll()` operation, as shown in the following, you can see that predicates are being pushed despite data transformations, because of the use of inverse functions. ##### Query Plan for the getAll Operation The case is the same for the other read methods `getByDeptName()`, `getByEmpName()`, and `getByEmpNo`(). Examining the corresponding query plans, you can see that predicates are being pushed regardless of the specific transformations because of the corresponding inverse functions.
| The `getByEmpName()` operation illustrates a typical case where the transformation involves performing a concatenation and the inverse function reverses the operation. In this case, N values are merged into 1 or vice versa. The `getByDeptName()` and `getByEmpNo()` operations are both 1:1 examples, transforming between numeric and string values.
## Related Topics ##### Concepts Using Inverse Functions to Improve Query Performance ##### How Tos Setting Up the Inverse Functions Sample ##### Reference Exploring the Inverse Functions Sample

Document generated by Confluence on Jan 13, 2009 15:16