Chapter 11. Transformer

11.1. What is a Transformer

It is not possible for the message providers to know what format of message is expected by every consumer. Therefore Transformers are used to enable the loose-coupling of message providers and message consumers. Transformers convert message content to various formats, thereby playing an important role in connecting service consumers and providers.

11.2. Transformation in SwitchYard

Transformation represents a change to the format or representation of a message's content. The representation of a message is the Java contract used to access the underlying content. For example, java.lang.String and org.example.MyFancyObject. The format of a message refers to the actual structure of the data itself. Examples of data formats include XML, JSON, CSV, and EDI. Here is an example of message content in XML format:
<MyBook>
  <Chapter1>
  <Chapter2>
</MyBook>
You can also represent XML in Java as a String. For example:
String content = "<MyBook>...";
Transformation plays an important role in connecting service consumers and providers, as the format and representation of message content can be quite different between the two. For example, a SOAP gateway binding is likely use a different representation and format for messages than a service offered by a Java Bean. In order to route services from the SOAP gateway to the Bean providing the service, the format and representation of the SOAP message needs to change. Implementing the transformation logic directly in the consumer or provider pollutes the service logic and can lead to tight coupling. SwitchYard allows you to declare the transformation logic outside the service logic and inject into the mediation layer at runtime.

11.3. Adding Transformation to a SwitchYard Application

You can specify transformation of message content in the descriptor of your SwitchYard application (switchyard.xml). The qualified name of the type being transformed from as well as the type being transformed to are defined along with the transformer implementation. This allows transformation to be a declarative aspect of a SwitchYard application, as the runtime automatically registers and executes transformers in the course of a message exchange. Here is an example of message content transformation:
<transforms>
   <transform.java bean="MyTransformerBean"
                   from="{urn:switchyard-quickstart-demo:orders:1.0}submitOrder"
                   to="java:org.switchyard.quickstarts.demos.orders.Order"/>
</transforms>	

11.4. Chaining Transformers

JBoss Fuse Service Works 6.0 allows you to chain transformers. Say you have a transformer that transforms from A to B and another that transforms from B to C. If you then have an invocation where the consumer is using type A and the provider is using type C, then the runtime will invoke the A->B and the B->C transformers to achieve A->C.
For example, for a SOAP message, you could define two transformers:
<transform:transform.java from="{http://web.service.com/}GetStatisticsResponse" to="{urn:web.service.com}StatisticsCData" bean="CDataReturn"/>
<transform:transform.jaxb from="{urn:web.service.com}StatisticsCData" to="java:com.sample.model.Statistics" contextPath="com.sample.model"/>
The first transformer transforms the SOAP reply which contains the GetStatisticsResponse element into an intermediate object which is just the content of the return element (CDATA containing the element), implemented in Java as follows:
@Named("CDataReturn")
public class CDataExtractor {

    @Transformer(from = "{http://web.service.com/}GetStatisticsResponse",
                 to = "{urn:web.service.com}StatisticsCData")
    public String transform(Element from) {
        String value = null;
        NodeList nodes = from.getElementsByTagName("return");
        if(nodes.getLength() > 0 ){
            value = nodes.item(0).getChildNodes().item(0).getNodeValue();
        }
        return value;
    }
}
The second transformer then takes care of transforming from the element to the Statistics Java model using JAXB.
JBoss Fuse Service Works 6.0 knows, from the contracts on the reference definitions, that it needs to go from {http://web.service.com/}GetStatisticsResponse to java:com.sample.model.Statistics and will automatically invoke both transformers to make that happen.

11.5. Adding a Transformer Using SwitchYard Editor

This section describes how to add a transformer to an application in the SwitchYard editor. The example in this section shows how to add a Smooks transformer.
  1. Select the main object (transform-smooks) in the SwitchYard editor.
    Configure Smooks transformations Using SwitchYard Editor

    Figure 11.1. Smooks Transformations in SwitchYard Editor

  2. Select the Transforms tab in the Properties view. The existing transformers are listed.
  3. Select Add to add new transformers.
    Description

    Figure 11.2. List of Transformers Under Properties View

    Note

    • Users are not able to add transformers unless they are required.
    • If no transformers are visible in the properties page, try updating the Maven project configuration by right-clicking the project and selecting MavenUpdate Project.

11.6. Message Content Type Names

Since transformations occur between named types (for example, from type A to type B), it is important to understand how the type names are derived. The type of the message is determined based on the service contract, which can be WSDL or Java.
  • WSDL
    For WSDL interfaces, the message name is determined based on the fully-qualified element name of a WSDL message. Here is an example of a WSDL definition:
    <definitions xmlns:tns="urn:switchyard-quickstart:bean-service:1.0">  
      <message name="submitOrder">
        <part name="parameters" element="tns:submitOrder"/>
      </message>
      <portType name="OrderService">
        <operation name="submitOrder">
          <input message="tns:submitOrder"/>
        </operation>
      </portType>
    </definitions>
    
    This yields the following message type name based on the message element name defined in the WSDL:
    {urn:switchyard-quickstart:bean-service:1.0}submitOrder
    
  • Java
    For Java interfaces, the message name consists of the full package name and the class name prefixed with "java:". Here is an example of a Java definition:
    package org.switchyard.example;
    public interface OrderService {
        void submitOrder(Order order);
    }
    
    This yields the following message type name:
    java:org.switchyard.example.Order
    
    You may override the default operation name generated for a Java interface. The @OperationTypes annotation provides this capability by allowing you to specify the input, output, and fault type names used for a Java service interface. For example, if you want to accept XML input content without any need for transformation to a Java object model, you can change the OrderService interface as shown below:
    package org.switchyard.example;
    public interface OrderService {
        @OperationTypes(in = "{urn:switchyard-quickstart:bean-service:1.0}submitOrder")
        void submitOrder(String orderXML);
    }
    This annotation can be useful if you want to maintain a tight control over the names used for message content.

11.7. Supported Transformations

11.7.1. Java

11.7.1.1. Java Transformer

You can create a Java-based transformer in SwitchYard using any of the following methods:
  • Implement the org.switchyard.transform.Transformer interface and add a <transform.java> definition to your switchyard.xml.
  • Annotate one or more methods on your Java class with @Transformer annotation.
When using the @Transformer annotation, the SwitchYard maven plug-in automatically generates the <transform.java> definition and adds them to the switchyard.xml packaged in your application. Here is an example of a Java class that produces the <transform.java> definition:
@Named("MyTransformerBean")
public class MyTransformer {
    @Transformer(from = "{urn:switchyard-quickstart-demo:orders:1.0}submitOrder")
    public Order transform(Element from) {
       // handle transformation here
    }
}
Here, the from and to elements of the @Transformer annotation are optional. You can use them to specify the qualified type name used during transformer registration. If not specified, the full class name of the method parameter is used as the from type and the full class name of the return type is used as the to type.
The CDI bean name specified by @Named annotation is used to resolve transformer class. If not specified, the class name of the transformer is used instead. Here is an example:
<transforms>
   <transform.java class="org.switchyard.quickstarts.demos.orders.MyTransformer"
                   from="{urn:switchyard-quickstart-demo:orders:1.0}submitOrder"
                   to="java:org.switchyard.quickstarts.demos.orders.Order"/>
</transforms>

Note

The bean attribute and class attribute are mutually exclusive.

11.7.2. JAXB

11.7.2.1. JAXB Transformer

SwitchYard automatically detects and adds the JAXB Transformations for your application deployment. For example, if you develop a CDI Bean Service and use JAXB generated types in the Service Interface, you do not need to configure any of the transformations. SwitchYard automatically detects their availability for your application and automatically applies them at the appropriate time during service invocation.
The JAXB transformer allows you to perform Java to XML and XML to Java transformations using JAXB (XML marshalling and unmarshalling). The JAXB Transformer is similar to the JSON Transformer configuration. It also requires a to and from configuration with one Java type and one QNamed XML type.
For example in the source file ObjectFactory.java, the factory methods represent the available marshallings/unmarshallings as shown below:
@XmlElementDecl(namespace = "http://com.acme/orders", name = "create")
public JAXBElement<CreateOrder> createOrder(CreateOrder value) {
    return new JAXBElement<Order>(_CreateOrder_QNAME, CreateOrder.class, null, value);
}
Here, the @XmlElementDecl annotation implies that the XML QName associated with the com.acme.orders.CreateOrder type is "{http://com.acme/orders}create". This means that you can have the following SwitchYard JAXB Transformer configurations:
<transform.jaxb from="{http://com.acme/orders}create" to="java:com.acme.orders.CreateOrder" />
<transform.jaxb from="java:com.acme.orders.CreateOrder" to="{http://com.acme/orders}create" />

11.7.3. JSON

11.7.3.1. JSON Transformer

The JSON transformer provides a basic mapping facility between POJOs and JSON (JSON marshalling and unmarshalling). Just like the JAXB Transformer, specification of the transformer requires a to and from specification with one Java type and one QNamed JSON type, depending on whether you are performing a Java to JSON or JSON to Java transformation.
Here is an example configuration of JSON to Java transformation:
<trfm:transform.json
            from="{urn:switchyard-quickstart:transform-json:1.0}order"
            to="java:org.switchyard.quickstarts.transform.json.Order"/>
Here is a sample configuration of Java to JSON transformation:
<trfm:transform.json
            from="java:org.switchyard.quickstarts.transform.json.Order"
            to="{urn:switchyard-quickstart:transform-json:1.0}order"/>

11.7.4. Smooks

11.7.4.1. Smooks Transformer

SwitchYard provides three distinct transformation models for Smooks:
  • XML to Java : Based on a standard Smooks Java Binding configuration.
  • Java to XML: Based on a standard Smooks Java Binding configuration.
  • Smooks : This is a normal Smooks transformation in which you must define which Smooks filtering result is to be exported back to the SwitchYard Message as the transformation result.
You can declare a Smooks transformation by including a <transform.smooks> definition in your switchyard.xml. Here is an example:
<transform.smooks config="/smooks/OrderAck_XML.xml"
                  from="java:org.switchyard.quickstarts.transform.smooks.OrderAck"
                  to="{urn:switchyard-quickstart:transform-smooks:1.0}submitOrderResponse"
                  type="JAVA2XML"/>
The Smooks and XSLT translators require an external configuration file that tells the translator how to go about its actions. In the example above, the config attribute points to a Smooks resource containing the mapping definition. The type attribute can be one of SMOOKS, XML2JAVA, or JAVA2XML.
For more information on Smooks and XSLT configuration files, see Red Hat JBoss Fuse Service Works Development Guide Volume 2: Smooks.
For more information on the elements that extend the abstract transform, see the /docs/schema/soa/org/switchyard/transform/config/model/v1/transform_<latest_version>.xsd.

11.7.5. XSLT

11.7.5.1. XSLT Transformer

You can perform transformations with the XSLT transformer using an XSLT. You can configure it by specifying the to and from QNames, and the path to the XSLT. Here is an example of XSLT Transformer configuration:
<transform.xslt from="{http://acme/}A" to="{http://acme/}B" xsltFile="com/acme/xslt/A2B.xslt"/>