XSLT Interceptor  Locate

Overview  Locate

XSLT Interceptor allows easy integration with other XML protocols using XSL Transformations. This feature can help application integration developers make on-the-fly transformations between two mutually incompatible Web services.

Imagine an example where a user has two Web services with incompatible operations. The user writes an XSLT style sheet and sets up an XSLT Interceptor that will transform SOAP messages on-the-fly to be compatible with the other side.

There are several possible ways to use and configure an XSLT Interceptor. The section Persistent Configuration describes how you can configure an XSLT Interceptor at deployment time. On the other hand, the section Runtime Configuration shows configuration with the help of the runtime API.

To utilize XSLT Interceptor, you must install the XSLT-Interceptor component. (For more information, please see XSLT-Interceptor in the Components chapter.)

Persistent Configuration  Locate

This section describes usage of the predefined XSLTInterceptor package and the more flexible custom configuration of XSLT Interceptor.

XSLT Interceptor Package  Locate

The easiest way to use XSLT Interceptor is by using our XSLTInterceptor package, which should be deployed during WSO2 SOA Enablement Server installation if you have chosen to install the XSLTInterceptor component. To use the XSLTInterceptor package in your application, create a dependency on it in your package's deployment descriptor and write the appropriate style sheets.

The deployment descriptor of the package that depends on the XSLTInterceptor package is shown in Example 281, Deployment Descriptor.

Example 281. Deployment Descriptor

<package
        name="ToDoListService" ...
        xmlns:xslt="http://systinet.com/wasp/app/xsltinterceptor" ...
        > ... 
    <dependency ref="xslt:xsltinterceptor"
                                         version="1.0"/> 
    ... 
</package>

Interceptors can process both incoming and outgoing messages for a service. XSLT Interceptor performs a transformation when a style sheet for the given direction is specified. The style sheet filename for the in direction must be in.xsl; for the out direction, the name must be out.xsl. These files should be placed in the root of the package structure that uses the interceptor, see Figure 29.

Figure 29. Structure of Package

Structure of Package

To use XSLT Interceptor on the client side, place the file WASP_HOME/lib/xsltinterceptor.jar in the Java VM CLASSPATH variable, together with the JAR file of your package; then start the client program. Of course, as mentioned above, your package must depend on the XSLTInterceptor package. WSO2 SOA Enablement Server automatically finds these packages and takes appropriate steps to use them. More information about client packages can be found in the section Client Package.

Another way to use XSLT Interceptor on the client side is to add your in.xsl and out.xsl to the copy of the WASP_HOME/lib/xsltinterceptor.jar file and place this copy in the Java VM CLASSPATH variable. In this case, you do not have to create the client package with a dependency on the XSLTInterceptor package, because a default one will be used.

Custom Configuration  Locate

The custom configuration of XSLT Interceptor can be used when you define more then one service endpoint or instance in your package, and all of them need their own XSL Transformation. In this case you must specify an interceptor instance for all service endpoints or instances. Example 282 shows the deployment descriptor of HelloService with two service endpoints.

Example 282. Custom Configuration of XSLT Interceptor

<?xml version="1.0" encoding="UTF-8"?>
<package name="HelloService"
    targetNamespace="http://wso2.com/package/example/
    applicationIntegration/xsltinterceptor"
    version="1.0" xmlns="http://wso2.com/wasp/package/1.1"
    xmlns:ns0="http://wso2.com/wsdl/example/applicationIntegration/xsltinterceptor/"
    xmlns:tns="http://wso2.com/package/example/applicationIntegration/xsltinterceptor"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xsd:schemaLocation="http://wso2.com/wasp/package/1.1">
    <license>http://wso2.com</license>
    <!-- HelloService1 endpoint -->
    <service-endpoint name="HelloService1" path="/HelloService1"
        processing="tns:HelloService1_processing"
        service-instance="tns:HelloService_inst" type="java">
        <wsdl service="ns0:JavaService" uri="HelloService.wsdl"/>
    </service-endpoint>
    <!-- HelloService2 endpoint -->
    <service-endpoint name="HelloService2" path="/HelloService2"
        processing="tns:HelloService2_processing"
        service-instance="tns:HelloService_inst" type="java">
        <wsdl service="ns0:JavaService" uri="HelloService.wsdl"/>
    </service-endpoint>
    <!-- HelloService service instance -->
    <service-instance
        implementation-class="examples.applicationIntegration.HelloService" 
        name="HelloService_inst"/>
    <!-- definition and configuration of xslt interceptor
    for endpoint HelloService1 -->
    <interceptor direction="in out"
        implementation-class="com.idoox.wasp.interceptor.XSLTInterceptor" 
        name="XSLTInterceptorInstance1">
        <configuration>
            <config>
                <inputXSL>customIn1.xsl</inputXSL>
                <outputXSL>customOut1.xsl</outputXSL>
            </config>
        </configuration>
    </interceptor>
    <!-- definition and configuration of xslt interceptor
    for endpoint HelloService2 -->
    <interceptor direction="in out"
        implementation-class="com.idoox.wasp.interceptor.XSLTInterceptor" 
        name="XSLTInterceptorInstance2">
        <configuration>
            <config>
                <inputXSL>customIn2.xsl</inputXSL>
                <outputXSL>customOut2.xsl</outputXSL>
            </config>
        </configuration>
    </interceptor>
    <!-- HelloService1 processing -->
    <processing name="HelloService1_processing">
        <use ref="tns:XSLTInterceptorInstance1"/>
    </processing>
    <!-- HelloService2 processing -->
    <processing name="HelloService2_processing">
        <use ref="tns:XSLTInterceptorInstance2"/>
    </processing>
</package>

The custom configuration is also applicable on the client sXSLT-Interceptoride, as you can see in Example 283.

Example 283. Custom Client Configuration of XSLT Interceptor

<?xml version="1.0" encoding="UTF-8"?>
<package client-package="true" name="HelloServiceClient"
    targetNamespace="http://wso2.com/package/example/
    applicationIntegration/xsltinterceptor"
    version="1.0" xmlns="http://wso2.com/wasp/package/1.1"
    xmlns:ns0="http://wso2.com/wsdl/example/applicationIntegration/xsltinterceptor/"
    xmlns:tns="http://wso2.com/package/example/applicationIntegration/xsltinterceptor"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xsd:schemaLocation="http://wso2.com/wasp/package/1.1">
    <license>http://wso2.com</license>
    <!-- service client -->
    <service-client port-type="ns0:HelloService" 
        processing="tns:HelloService_processing"/>
    <!-- definition and configuration of xslt interceptor
   for HelloService service client -->
    <interceptor direction="in out"
        implementation-class="com.idoox.wasp.interceptor.XSLTInterceptor" 
        name="XSLTInterceptorInstance">
        <configuration>
            <config>
                <inputXSL>customIn.xsl</inputXSL>
                <outputXSL>customOut.xsl</outputXSL>
            </config>
        </configuration>
    </interceptor>
    <!-- HelloService processing -->
    <processing name="HelloService_processing">
        <use ref="tns:XSLTInterceptorInstance"/>
    </processing>
</package>

Runtime Configuration  Locate

The service's configuration via the runtime API is transient: when the server is shut down, this configuration ceases to exist and the service needs to be reconfigured when the server is restarted. Runtime configuration of XSLT Interceptor on the client side is shown in a simple way in Example 284 and on the service side in Example 285. A client for the service-side configuration is shown in Example 286. All of these examples use the XSLTInterceptor(java.io.InputStream, java.io.InputStream) constructor, where the first parameter is the input stream of the style sheet for the in direction and the second parameter is the input stream for the out direction.

Example 284. Client Configuration

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.applicationIntegration.xsltinterceptor;

import com.idoox.wasp.interceptor.XSLTInterceptor;

import example.basics.invocation.HelloService;

import org.systinet.wasp.webservice.Interceptors;
import org.systinet.wasp.webservice.Registry;
import org.systinet.wasp.webservice.ServiceClient;

import java.io.FileInputStream;


public final class HelloClient {
    private static String serviceWSDLPath = "/demo/basic/HelloService/wsdl";

    public static void main(String[] args) throws Exception {
        String serverURL =
            System.getProperty("wso2.demo.server.url",
                "http://localhost:6060");
        ServiceClient serviceClient =
            ServiceClient.create(serverURL + serviceWSDLPath, HelloService);

        // create XSLTnterceptor and setup service client
        XSLTInterceptor xsltInterceptor =
            new XSLTInterceptor(new FileInputStream("in.xsl"),
                new FileInputStream("out.xsl"));
        serviceClient.getInterceptors()
                     .insert(xsltInterceptor, Interceptors.DIRECTION_INOUT);

        // lookup service
        HelloService helloService =
            (HelloService) Registry.lookup(serviceClient);

        // call HelloServiceImpl and print out a response message
        System.out.println(helloService.hello("Hello service!"));
    }
}

Example 285. Service Configuration

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.applicationIntegration.xsltinterceptor;

import com.idoox.wasp.interceptor.XSLTInterceptor;

import org.idoox.wasp.types.RequestMessageAttachment;

import org.systinet.wasp.webservice.Current;
import org.systinet.wasp.webservice.Interceptors;
import org.systinet.wasp.webservice.ServiceEndpoint;

import java.io.IOException;

import javax.xml.transform.TransformerConfigurationException;


public class HelloServiceImpl {
    private final static String HELLO_WORLD =
        "Hello World, this is WSO2" + " SOA Enablement Service. You have sent me : ";

    // runtime registered interceptor's name
    XSLTInterceptor xsltInterceptor;

    /**
     * Registers XSLTInterceptor
     * @param inXSL the stylesheet filename for the in direction
     * @param outXSL the stylesheet filename for the out direction
     * @throws IOException when an error occurs
     * @throws TransformerConfigurationException when an error occurs
     */
    public void init(
        RequestMessageAttachment inXSL,
        RequestMessageAttachment outXSL)
        throws IOException, 
            TransformerConfigurationException {
        // gets endpoint
        ServiceEndpoint endpoint =
            Current.getServiceEndpointContext()
                   .getServiceEndpoint();

        // creates XSLTInterceptor instance
        xsltInterceptor =
            new XSLTInterceptor(
                inXSL.getData(),
                outXSL.getData());

        // inserts interceptor
        endpoint.getInterceptors()
                .insert(xsltInterceptor, Interceptors.DIRECTION_INOUT);
    }

    /**
     * Removes XSLTInterceptor
     */
    public void clean() {
        Interceptors interceptors =
            Current.getServiceEndpointContext()
                   .getServiceEndpoint()
                   .getInterceptors();
        interceptors.remove(xsltInterceptor);
    }

    /**
     * Returns 'Hello world' message
     * @param message
     * @return 'Hello world'
     */
    public String hello(String message) {
        return HELLO_WORLD + message;
    }
}

Example 286. Client for Service Configuration

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.applicationIntegration.xsltinterceptor;

import org.idoox.wasp.types.RequestMessageAttachment;

import org.systinet.wasp.webservice.Registry;

import java.io.FileInputStream;


public class HelloServiceClient {
    private static String serviceWSDLPath = "/demo/basic/HelloService/wsdl";

    public static void main(String[] args) throws Exception {
        String serverURL =
            System.getProperty("wso2.demo.server.url",
                "http://localhost:6060");

        // lookup of HelloServiceImpl
        HelloService helloService =
            (HelloService) Registry.lookup(serverURL + serviceWSDLPath,
                HelloService.class);

        // init service configuration
        RequestMessageAttachment attachmentIn = new RequestMessageAttachment();
        attachmentIn.setData(new FileInputStream("in.xsl"));

        RequestMessageAttachment attachmentOut =
            new RequestMessageAttachment();
        attachmentOut.setData(new FileInputStream("out.xsl"));
        helloService.init(attachmentIn, attachmentOut);

        // call service and print out a response message from HelloService
        System.out.println(helloService.hello("Hello service!"));

        // clean service configuration
        helloService.clean();
    }
}

For details about the runtime API, see Runtime Publishing under Publishing Web services in the Developer's Guide. This section begins with the Registry chapter.

Configuration Priority  Locate

The following list shows the priority when more types of configuration occur for one XSLT Interceptor instance:

  1. Runtime configuration

  2. Custom configuration

  3. Use of the XSLT Interceptor

Passed Parameters  Locate

XSLT Interceptor passes the following parameters to the style sheets:

  • PARAM_URI

  • URI of connection whose messages are intercepted

  • PARAM_PATH

  • path of the URI

  • PARAM_CONTEXT_PATH

  • context path of the URI

  • PARAM_LOCATION

  • location of the URI

More information about the meaning of parameters can be found in the Javadoc for org.idoox.transport.URI.

There is more information about Interceptors in the chapter Interceptors in the Message Processing section.

A demo in the directory WASP_HOME/demo/advanced/xslt shows the use of XSLT Interceptor to transform outgoing SOAP messages to HTML.

[Note]Note

In the case of Multi-part messages, transformation is applied only to the first part of the message.

Using a Different XSLT Processor  Locate

WSO2 SOA Enablement Server comes bundled with the Xalan XSLT processor, Version 2.5.1. It is located in the file xalan.jar and it is automatically loaded together with wasp.jar. However, it is possible to use a different XSLT processor, such as Saxon.

To do this on the client side, place the JAR file containing your XSLT processor in your client CLASSPATH and on server side place the JAR in WSO2 SOA Enablement Server CLASSPATH. Then you can use both persistent and runtime configuration of the XSLT Interceptor. Example 287 shows persistent configuration for Saxon. Note the transformerFactory and parserFactory elements which specify the appropriate implementation classes.

Example 287. Persistent Configuration for Saxon

<package name="HelloService"
 ...>

 ...

 <!-- definition and configuration of xslt interceptor -->

<interceptor name="XSLTInterceptorInstance"
             implementation-class="com.idoox.wasp.interceptor.XSLTInterceptor"
             direction="in out">
 <configuration><config>
   <inputXSL>in.xsl</inputXSL>
   <outputXSL>out.xsl</outputXSL>
   <transformerFactory>com.icl.saxon.TransformerFactoryImpl</transformerFactory>
   <parserFactory>com.icl.saxon.aelfred.SAXParserFactoryImpl</parserFactory>
   <documentBuilderFactory/>
 </config></configuration>
</interceptor>
  ...
</package> 

In the case of runtime configuration, you should use the XSLTInterceptor(InputStream inputXSL, InputStream outputXSL, String transformerFactory, String parserFactory, String documentBuilderFactory) constructor for setting particular values. It is not necessary to specify all the properties, so you can set null.

Another way, on the client side, is placing the JAR file containing the XSLT processor as the first entry in your client classpath. It is necessary that this JAR file contains the META-INF/services directory, setting the properties javax.xml.transform.TransformerFactory and javax.xml.parsers.SAXParserFactory to the implementation class of your XSLT processor transformer factory and SAX parser factory. This is already true for Saxon 6.2 and above, but you may need to add this manually to other XSLT processor implementations.