Building a WS-SOAP Proxy with Mule ESB

A common integration scenario is that a company/organisation has a old internal web-service that they want to expose as a public interface.
Often these internal services have a less than ideal interface which is often auto-generated from some business logic so you do not want to simply expose the existing contract. Instead we want to have a interface more suited for use by external entities. However it is not always practical or possible to rewrite the internal service.

The solution is to build a SOAP proxy with transformation.

Lets say we have a internal service that gets a name and returns a greeting for that name. Here is a example of the request and response for this imaginary internal service.

EchoService request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:echo="http://echo.example.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <echo:echo>
         <arg0>Pontus</arg0>
      </echo:echo>
   </soapenv:Body>
</soapenv:Envelope>
EchoService response
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:echo="http://echo.example.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <echo:echoResponse>
         <!--Optional:-->
         <return>Hello Pontus</return>
      </echo:echoResponse>
   </soapenv:Body>
</soapenv:Envelope>

As you can see the inner service has alot to wish for when it comes to naming. Fortunately with Mule ESB it is simple to create a SOAP proxy that remedies this.

The Mule flow starts with a inbound HTTP endpoint and a CXF Proxy service which exposes the desired interface.

The main flow
1
2
3
4
5
6
7
 <flow name="SOAP2SOAPFlow2" doc:name="SOAP-2-SOAP proxy using CXF">
    <http:inbound-endpoint exchange-pattern="request-response" 
        host="localhost" port="8081" doc:name="HTTP"/>
    <cxf:proxy-service namespace="urn:greeter:GreeterResponder:1" 
        service="GreeterResponderService" payload="body" 
        wsdlLocation="schemas/interactions/GreeterInteraction/GreeterInteraction_1.0.wsdl" 
        enableMuleSoapHeaders="false" doc:name="SOAP"/>        

The payload from these initial steps will be the body of the incomming SOAP request. So we want to translate this to comply with the interface of the inner service.

8
9
10
11
12
    <mulexml:xslt-transformer 
        maxIdleTransformers="2" maxActiveTransformers="5" 
        outputEncoding="UTF-8" doc:name="Transform from outer to inner" 
        xsl-file="transform-outer2inner.xslt" encoding="UTF-8" 
        returnClass="java.lang.String"/>

The default return type from the XSLT transformer is a byte array. Since we want the payload as a String we set the returnClass attribute.

After this we want to call the inner service and then get the response body. This is the only really tricky bit. Since we only want the SOAP body from the response we must let the CXF component handle the response before we send it to the transformation. This is done by breaking out this part into a subflow.

22
23
24
25
26
<flow name="CallInnerEndpoint">
    <cxf:proxy-client payload="body" enableMuleSoapHeaders="true"/ >
    <http:outbound-endpoint exchange-pattern="request-response" 
        address="http://localhost:8088/mockEchoBinding" doc:name="HTTP" />
</flow>

This subflow is then called from the main flow

13
    <flow-ref name="CallInnerEndpoint" />

And finaly we transform the response body into a response that complies with the external interface.

14
15
16
17
18
19
    <mulexml:xslt-transformer maxIdleTransformers="2" 
        maxActiveTransformers="5" outputEncoding="UTF-8" 
        doc:name="Transform from inner response to outer response" 
        xsl-file="transform-inner2outer.xslt" encoding="UTF-8" 
       returnClass="java.lang.String"/>
</flow>

And with that we're done and can start using the public interface.

Greeter request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:greeter:GreeterResponder:1">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:GreetingRequest>
         <urn:Name>Pontus</urn:Name>
      </urn:GreetingRequest>
   </soapenv:Body>
</soapenv:Envelope>
Greeter response
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:greeter:GreeterResponder:1">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:GreetingResponse>
         <urn:Greeting>Hello Pontus</urn:Greeting>
      </urn:GreetingResponse>
   </soapenv:Body>
</soapenv:Envelope>

Full code example is available at github.