Author: Ricardo Ferreira
One of the most common tasks performed during the creation of integrations in ICS (Integration Cloud Service) is the implementation of mappings. In a nutshell, mappings are the resources that ICS uses to allow messages coming from the configured source application to be sent to the configured target application. Failure in properly defining and configuring these mappings directly impacts how integrations are going to behave while sending messages downstream.
In order to build mappings in ICS, users make use of the mapping editor. The mapping editor allows for the creation of complex XPath expressions via an intuitive drag-and-drop interface. Besides the support for XPath expressions, it is also possible to use built-in XSLT functions available within the Mapping Components section of the mapping editor, as shown in figure 1.
Figure 1: ICS mapping editor with the functions palette expanded.
However, it is not uncommon to find situations in which the set of built-in functions is not adequate to perform a specific data handling operation. When that happens, most people using ICS feel they’ve hit a roadblock due to the fact that there is no way to simply add a custom function. While there is always the possibility to open an SR (Service Request) within Oracle and request an enhancement, sometimes this is not possible because the ongoing project requires at least a workaround in order to be able to finish the use case in a timely manner.
This blog is going to show how classes from ICS's Fusion Middleware foundation can be leveraged to provide custom data handling in mappings. To illustrate this, the following sections will show how to perform Base64 data decoding, using a utility class from the Oracle WebLogic API.
In contrast to what many people think, ICS is not a black box. You can access pretty much everything that is generated by ICS when you export the integration, as shown in figure 2. Once you have access to the integration archive file, you can see what ICS generated for you and in case of mappings, even change it.
Figure 2: Generating an integration archive.
With this option in mind, most people who are familiar with programming in XSLT feel more comfortable in handling each mapping directly; by using its own programming constructs if of course, it is valid under the XSLT specification. In order to be able to write XSLT code for the mappings, the first thing you need to do is locate the .XSL file that handles the mapping under the integration archive structure.
Be aware that .XSL files are only generated if you perform at least one initial mapping. Therefore, you must create a mapping using the visual editor to generate the file. Once generated, you can change it to suit your needs.
Typically, the location of the .XSL files within the integration archive use the following filename pattern:
Each mapping in the integration generates a processor_XXX folder. For example, in a typical SOAP-based request-reply integration, there will be at least three mappings: one for the request flow, one for the response flow and one for the fault flow. In this particular case, you can expect that there will be three processor_XXX folders under the resources folder. "XXX" in this context will be a system-generated identifier for each processor, which has the responsibility to uniquely identify that component within the integration. Figure 3 shows an example of a generated .XSL file. We are going to change that file in order to include a Java native function that performs Base64 decoding.
Figure 3: Example of .XSL generated file.
First, you should notice that there is a comment in the .XSL file that states where you should make any code changes. That can be observed in the "User Editing allowed BELOW this line" code comment. Unless you know exactly what you are doing please do not modify other portions of the code or you will end up breaking the code and will probably experience runtime errors.
Second, before calling any custom function in XSLT, you need to provide the namespace that defines that function. Specifically, you need to provide a namespace declaration that specifies which Java class is being used for the custom function. Figure 4 shows how to declare a custom function for the Base64 decoding use case, and how to use that function within the XSLT code.
Figure 4: Defining and using custom functions in XSLT.
The namespace declaration should specify a fully qualified Java class, and associate this class to a prefix. In the example shown in figure 4; the weblogic.apache.xerces.impl.div.util.Base64 class was associated with the "b64" prefix, so it can be used across the XSLT script by mentioning this prefix. Keep in mind that not all Java classes can be used as a custom function. In order to work, the class should expose only static methods, and the data types used must be simple types present in the XML/XSLT specification. Be aware of data type conversion as well. The values passed by argument to the functions must match with the types defined in the method, just like the value returned by the method must match with the enclosing tag that will receive the value.
Third, you have to save all changes back to the integration archive, and re-import the archive into ICS. When you do this, you can continue your development work using the ICS UI, or just activate it to start testing it.
Figure 5: Importing the integration archive.
While applying this technique in your integrations, please do so with care. Be particularly careful with which Java classes you chose to use it. Oracle provides no guarantees that some specific class will be always available on ICS's Fusion Middleware foundation. For this reason, you may want to prefer classes that belong to the JDK and/or any class that you relatively certain is available under the ICS runtime architecture.