Over a million developers have joined DZone.

Mule WS Proxy Namespace Rewriting

· Integration Zone

Is iPaaS solving the right problems? Not knowing the fundamental difference between iPaaS and dPaaS could cost you down the road. Brought to you in partnership with Liaison Technologies.

Today I saw two things I cannot recall having seen before:

The first thing was a WSDL for a web service in which the target namespace and the service address were identical. As far as I know, there is nothing that disallows this, it is only peculiar – at least to me.

The second thing was that when I put a Mule web service proxy in front of the web service exposing the WSDL mentioned above, not only the port address of the web service endpoint were rewritten, but also the target namespace.
If I expected you to believe my word, then this blog post would end here. However, I do not expect you to believe my word and I wanted to examine this behaviour more closely.

Before we look at some hard proof, I just want to mention that I have used Mule CE 3.4.0 when implementing the example program in this post.

Preparations

In your favourite Eclipse-based IDE with the MuleStudio plug-in installed, create a Mule project. In this Mule project, create two Mule flows; one named ”helloserviceflow” and another named ”wsproxybug”.
In the flow ”helloserviceflow”, paste the following Mule flow configuration:

<?xml version="1.0" encoding="UTF-8"?>
<mule
    xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf"
    xmlns="http://www.mulesoft.org/schema/mule/core"
    xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
    xmlns:spring="http://www.springframework.org/schema/beans"
    xmlns:test="http://www.mulesoft.org/schema/mule/test"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/cxf http://www.mulesoft.org/schema/mule/cxf/current/mule-cxf.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/test http://www.mulesoft.org/schema/mule/test/current/mule-test.xsd">

    <spring:beans>
        <spring:bean id="helloService" class="se.ivankrizsan.mule.wsproxybug.HelloService"/>
    </spring:beans>

    <flow name="HelloServiceFlow">
        <inbound-endpoint
            address="http://localhost:8182/services/GreetingService"
            exchange-pattern="request-response"/>
        <cxf:jaxws-service serviceClass="se.ivankrizsan.mule.wsproxybug.HelloService"/>
        <component>
            <spring-object bean="helloService"/>
        </component>
    </flow>
</mule>

Create a Java-class that implements the HelloService:

package se.ivankrizsan.mule.wsproxybug;

import java.util.Date;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

/**
* SOAP web service endpoint implementation class that implements a service that extends greetings.
* 
* @author Ivan Krizsan
*/
@WebService(targetNamespace = "http://localhost:8182/services/GreetingService")
public class HelloService {
    /**
    * Greets the person with the supplied name.
    * 
    * @param inName Name of person to greet.
    * @return Greeting.
    */
    @WebResult(name = "greeting")
    public String greet(@WebParam(name = "inName") final String inName) {
        return "Hello " + inName + ", the time is now " + new Date();
    }
}

Note that in the @WebService annotation I have specified the target namespace of the web service to a URL that is identical to the address of the inbound endpoint in the HelloServiceFlow.

The final part of the preparations consist of installing the HttpRequester add-on in Mozilla Firefox. This add-on makes it possible to send different kinds of HTTP requests (GET, POST, PUT etc) and examine the result from within Firefox.

Proxy the Webservice

In the ”wsproxybug” flow, paste the following Mule configuration:

<?xml version="1.0" encoding="UTF-8"?>
<mule
    xmlns:http="http://www.mulesoft.org/schema/mule/http"
    xmlns:pattern="http://www.mulesoft.org/schema/mule/pattern"
    xmlns="http://www.mulesoft.org/schema/mule/core"
    xmlns:spring="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    version="CE-3.4.0"
    xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/http
http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd 

http://www.mulesoft.org/schema/mule/pattern
http://www.mulesoft.org/schema/mule/pattern/current/mule-pattern.xsd

http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-current.xsd

http://www.mulesoft.org/schema/mule/core
http://www.mulesoft.org/schema/mule/core/current/mule.xsd">

    <pattern:web-service-proxy name="WSProxyBugFlow">
        <http:inbound-endpoint address="http://localhost:8190/proxiedservices/GreetingService" />
        <http:outbound-endpoint address="http://localhost:8182/services/GreetingService" />
    </pattern:web-service-proxy>
</mule>

For those new to the Mule web service proxy pattern, I just want to mention that this pattern makes it very easy to proxy a web service by exposing it on the URL specified in the inbound endpoint. The URL of the web service that is to be proxied is specified in outbound endpoint, which the astute reader will notice is identical to the URL of the HelloService that was part of the preparations.

Run the Example Program

We are now ready to run the example program. Right-click on the Mule project in Eclipse and select Run As -> Mule Application.
After some time, there should be output in the console indicating that the Mule application was started successfully.

Examine the HelloService

As a first step, we take a look at the HelloService to learn what data it presents about itself:
In Firefox, open the HttpRequester add-on and paste the URL http://localhost:8182/services/GreetingService?wsdl in the upper left part of the dialog. Then click the GET button (third from the left under the URL field). The result should look like this:

Using HttpRequester we can see, among other things that:

  • The request took 47 ms to complete.
    This is in my environment – the time may vary depending on your environment.
  • The content type of the response is ”text/xml”.
  • The namespace in the WSDL is the same that we specified in the @WebService annotation in the HelloService class earlier:
<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions
 name="HelloServiceService"
 targetNamespace="http://localhost:8182/services/GreetingService"
 xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:tns="http://localhost:8182/services/GreetingService"
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">

The port of the service, where the endpoint address of the service is specified, looks like this:

<wsdl:port binding="tns:HelloServiceServiceSoapBinding" name="HelloServicePort">
 <soap:address location="http://localhost:8182/services/GreetingService"/>
</wsdl:port>

Examine the Service Proxy

Let’s look at the proxied version of the HelloService.
Repeat the exercise of sending a GET request for a WSDL in HttpRequester, but this time use this URL: http://localhost:8190/proxiedservices/GreetingService?wsdl
The result should look something like this:

Examining the result more closely, we see that:

  • It took more than three times as long to complete the request through the proxy.
    In my case 175 ms through the proxy compared to 47 ms direct access. Perhaps it would be more just to say that the proxy added about 125 ms overhead to a request.
  • The content type of the response returned by the proxy is ”text/plain”.
  • The target namespace of the WSDL has changed:
    ”Computer” is the name of my computer and the proxy has apparently replaced ”localhost” with the resolved name of my computer’s address.
    This was not quite expected behaviour of the proxy.
<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions
 name="HelloServiceService" 
 targetNamespace="http://Computer:8190/proxiedservices/GreetingService"
 xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:tns="http://Computer:8190/proxiedservices/GreetingService"
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">

The port of the service looks like this:
The proxy did this part well.

<wsdl:port binding="tns:HelloServiceServiceSoapBinding" name="HelloServicePort">
   <soap:address location="http://Computer:8190/proxiedservices/GreetingService"/>
</wsdl:port>

The Mule WSProxy Class

The web service proxy in Mule is implemented by the class org.mule.module.ws.construct.WSProxy, which in turn contains a number of inner classes. One of the inner classes contain a method named modifyServiceAddress, which is responsible for rewriting the service address in a WSDL. Unfortunately, it uses the method replaceAll on the String class which result in the behaviour we have seen.
What is even more unfortunate is the design of the WSProxy class with private inner classes which, although there is a constructor taking an instance of AbstractProxyRequestProcessor as a parameter, I cannot see how to create a subclass that resides outside of the WSProxy class of the AbstractProxyRequestProcessor class.

Alternatives?

Well, are there any alternatives?
Of course you can implement something of your own using Mule, while you wait for this issue to be fixed: https://www.mulesoft.org/jira/browse/MULE-7466
How about non-Mule alternatives?
I will leave pure HTTP proxy implementations of various kinds out of the discussion since they will not be able to rewrite service addresses in WSDLs. However, it may be worthwhile to ask yourself if you really need a web service proxy that is able to rewrite service addresses in WSDLs.

So, lets assume that you must have a web service proxy that is able to rewrite service addresses. What to do?

Apache Camel

If alternatives that do not use Mule may be considered then Apache Camel is definitely a candidate. There is even an example that implements a web service proxy. In the 2.13.0 distribution, it is located in the directory ”camel-example-cxf-proxy” in the ”examples” directory.

I took the liberty of modifying the proxy example slightly. First of all, I wanted pure proxying without any modifications to requests. Second I adapted the proxy to HelloService. The result looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:camel="http://camel.apache.org/schema/spring"
    xmlns:cxf="http://camel.apache.org/schema/cxf"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       
       http://camel.apache.org/schema/spring
       http://camel.apache.org/schema/spring/camel-spring.xsd
       
       http://camel.apache.org/schema/cxf
       http://camel.apache.org/schema/cxf/camel-cxf.xsd">

    <!--
        Endpoint of the web service proxy which:
        Has the address specified by the address attribute.
        Exposes the port specified by the endpointName attribute in the
        service specified by the serviceName attribute from the WSDL
        specified by the wsdlURL attribute.
        
        Note how the namespace of the WSDL is specified and its namespace
        prefix is used in the port and service names.
    -->
    <cxf:cxfEndpoint id="proxyFrontEnd"
        address="http://localhost:8290/proxiedservices/GreetingService"
        endpointName="gs:HelloServicePort"
        serviceName="gs:HelloServiceService"
        wsdlURL="http://localhost:8182/services/GreetingService?wsdl"
        xmlns:gs="http://localhost:8182/services/GreetingService" />

    <!--
        Apache Camel route that proxies a web service and logs requests
        and responses to the proxy.
    -->
    <camelContext xmlns="http://camel.apache.org/schema/spring">

        <endpoint id="callRealWebService" uri="http://localhost:8182/services/GreetingService" />

        <route>
            <from uri="cxf:bean:proxyFrontEnd?dataFormat=MESSAGE" />
            <!-- Log incoming request. -->
            <to uri="log:input" />
            <!-- Invoke the web service that is being proxied. -->
            <to ref="callRealWebService" />
            <!-- Log outgoing response. -->
            <to uri="log:output" />
        </route>
    </camelContext>
</beans>

Note that when starting the Apache Camel proxy, the HelloService must be up and running.

So does it work?

As can be seen from the above picture, it does work. The content type is text/xml, the target namespace of the WSDL is unchanged and, as can be seen below, the service endpoint address has been rewritten. The overhead added by the Camel proxy is about the same as that of the Mule proxy.

<wsdl:port binding="tns:HelloServiceServiceSoapBinding" name="HelloServicePort">
   <soap:address location="http://Computer:8190/proxiedservices/GreetingService"/>
</wsdl:port>

Membrane

If there are a lot of web services that are to be proxied and/or configuration of web service proxies in a GUI is preferred, then the Membrane Service Proxy may be an option.

Discover the unprecedented possibilities and challenges, created by today’s fast paced data climate and why your current integration solution is not enough, brought to you in partnership with Liaison Technologies.

Topics:

Published at DZone with permission of Ivan K. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}