Monday, July 25, 2011

Mule - Extending Mule to Create custom Transformers

One can extend existing Mule Modules, transports, etc to create a customized ones based on your project needs. The advantages of extending or customizing Mule with your own namespaces are

  • Class names are removed from XML so that implementation details are hidden.
  • All objects introduced by the module are self-contained by a namespace.
  • The schema provides a domain-specific language (DSL) for the module where all objects and properties are described in the schema with type validation.
  • The schema can provide additional validation for types, value ranges, and required properties.

More detailed explanation on creating your own mule namespaces can be found at http://www.mulesoft.org/documentation/display/MULE2USER/Creating+a+Custom+XML+Namespace

The following example creates a new module that contains a transformer to log the request and do nothing else. One can easily start with this transformer and customize them based on project needs.

1. Create a new mule-module-archetype using maven from the command line.

>echo %M2_HOME%
C:\Vijay\Office\Softwares\apache-maven-3.0.3

>cd C:\Office\MuleWorkspace

>mvn org.mule.tools:mule-module-archetype:2.2.1:create -DartifactId=LoggerModule -DmuleVersion=2.2.1 -DarchetypeArtifactId=mule-module-archetype

>cd LoggerModule

>mvn eclipse:eclipse

2. Open Eclipse and Open the Logger Module as an existing java project. The Maven Plugin would by default create the folder structures for you.

Logger Module
3. Updating the XSD to define your own transformer.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://www.mulesource.org/schema/mule/loggermodule/2.2"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:mule="http://www.mulesource.org/schema/mule/core/2.2"
    xmlns:schemadoc="http://www.mulesource.org/schema/mule/schemadoc/2.2"
    targetNamespace="http://www.mulesource.org/schema/mule/loggermodule/2.2"
    elementFormDefault="qualified" attributeFormDefault="unqualified">

    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:import namespace="http://www.mulesource.org/schema/mule/core/2.2"
        schemaLocation="http://www.mulesource.org/schema/mule/core/2.2/mule.xsd" />
    <xsd:import namespace="http://www.mulesource.org/schema/mule/schemadoc/2.2"
        schemaLocation="http://www.mulesource.org/schema/mule/schemadoc/2.2/mule-schemadoc.xsd" />

    <xsd:annotation>
        <xsd:documentation></xsd:documentation>
        <xsd:appinfo>
            <schemadoc:short-name>LoggerModule
            </schemadoc:short-name>
            <schemadoc:page-title>LoggerModule Module
            </schemadoc:page-title>
        </xsd:appinfo>
    </xsd:annotation>


    <xsd:element name="logger-transformer" type="loggerTransformerType"
        substitutionGroup="mule:abstract-transformer">
        <xsd:annotation>
            <xsd:documentation>
                Logs the incoming object details
            </xsd:documentation>
        </xsd:annotation>
    </xsd:element>

    <xsd:complexType name="loggerTransformerType">
        <xsd:complexContent>
            <xsd:extension base="mule:abstractTransformerType">
                <xsd:attribute name="throwExceptionOnFault"
                    type="xsd:boolean">
                    <xsd:annotation>
                        <xsd:documentation>
                            Whether or not to throw an
                            exception when a
                            fault is occured.
                        </xsd:documentation>
                    </xsd:annotation>
                </xsd:attribute>
                <xsd:attribute name="customMsg" type="xsd:string"
                    use="optional">
                    <xsd:annotation>
                        <xsd:documentation>
                            Custom Message that has
                            to be
                            logged.
                        </xsd:documentation>
                    </xsd:annotation>
                </xsd:attribute>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
</xsd:schema>

4. Define the transformer and register your transformer by indicating how to parse your XML elements in mule-config.xml.

LoggerTransformer.java

package org.mule.modules.loggermodule;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mule.api.MuleMessage;
import org.mule.api.transformer.TransformerException;
import org.mule.transformer.AbstractMessageAwareTransformer;

public class LoggerTransformer extends AbstractMessageAwareTransformer {

    private static final Log LOG = LogFactory.getLog(LoggerTransformer.class);

    private String customMsg;

    @Override
    public Object transform(MuleMessage muleMessage, String encoding)
            throws TransformerException {

        if (LOG.isInfoEnabled()) {

            LOG.info(customMsg);
            LOG.info("Payload : " + muleMessage.getPayload());
        }

        return muleMessage;
    }

    public String getCustomMsg() {
        return customMsg;
    }

    public void setCustomMsg(String customMsg) {
        this.customMsg = customMsg;
    }
}

LoggerModuleNamespaceHandler.java

/*
 * Generated by the Mule project wizard. http://mule.mulesource.org
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.modules.loggermodule.config;

import org.mule.config.spring.handlers.AbstractMuleNamespaceHandler;
import org.mule.config.spring.parsers.specific.TransformerDefinitionParser;
import org.mule.modules.loggermodule.LoggerTransformer;

/**
 * Registers a Bean Definition Parser for handling elements defned in
 * META-INF/mule-loggermodule.xsd
 * 
 */
public class LoggerModuleNamespaceHandler extends AbstractMuleNamespaceHandler {
    public void init() {
        registerBeanDefinitionParser("logger-transformer",
                new TransformerDefinitionParser(LoggerTransformer.class));
    }
}

5. With this your new namespace is complete. You can create the jar using Right click->Run As->Maven Package.

6. Include the jar file in your project and use your own name space in mule.config.xml

mule-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesource.org/schema/mule/core/2.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vm="http://www.mulesource.org/schema/mule/vm/2.2"
    xmlns:http="http://www.mulesource.org/schema/mule/http/2.2"
    xmlns:data-int="http://www.mulesoft.com/schema/mdi/data-int/2.2"
    xmlns:saaj="http://www.mulesource.org/schema/mule/saaj/2.2"
    xmlns:mule-xml="http://www.mulesource.org/schema/mule/xml/2.2"
    xmlns:my-logger="http://www.mulesource.org/schema/mule/loggermodule/2.2"
    xsi:schemaLocation="
       http://www.mulesource.org/schema/mule/core/2.2 http://www.mulesource.org/schema/mule/core/2.2/mule.xsd
       http://www.mulesource.org/schema/mule/vm/2.2 http://www.mulesource.org/schema/mule/vm/2.2/mule-vm.xsd
       http://www.mulesource.org/schema/mule/http/2.2 http://www.mulesource.org/schema/mule/http/2.2/mule-http.xsd
       http://www.mulesoft.com/schema/mdi/data-int/2.2 http://www.mulesoft.com/schema/mdi/data-int/2.2/mule-module-data-int.xsd
       http://www.mulesource.org/schema/mule/saaj/2.2 http://www.mulesource.org/schema/mule/saaj/2.2/mule-saaj.xsd
       http://www.mulesource.org/schema/mule/xml/2.2 http://www.mulesource.org/schema/mule/xml/2.2/mule-xml.xsd
       http://www.mulesource.org/schema/mule/loggermodule/2.2 http://www.mulesource.org/schema/mule/loggermodule/2.2/mule-loggermodule.xsd">

    <model>
        <service name="ShippingService">
            <inbound>
                <http:inbound-endpoint
                    address="http://localhost:9090/ShippingService"
                    synchronous="true">
                    <transformers>

                        <!-- Transform Incoming Soap Message to String -->
                        <saaj:soap-message-to-document-transformer />
                        <mule-xml:dom-to-xml-transformer
                            returnClass="java.lang.String" />

                        <my-logger:logger-transformer
                            customMsg="Incoming Payload" />
                    </transformers>
                    <response-transformers>

                        <my-logger:logger-transformer
                            customMsg="Outgoing Payload" />

                        <!-- Transform XML to Soap Response -->
                        <mule-xml:xml-to-dom-transformer
                            returnClass="org.w3c.dom.Document" />
                        <saaj:document-to-soap-message-transformer
                            propagateHeaders="false" />
                    </response-transformers>
                </http:inbound-endpoint>
            </inbound>
            <outbound>
                <pass-through-router>
                    <vm:outbound-endpoint path="routeData"
                        synchronous="true" />
                </pass-through-router>
            </outbound>
        </service>

    </model>

</mule>

1 comment: