How to call a WebService with Spring-WS through a Proxy

in analogy to some other well known templates within the spring framework, which encapsulate most of the boiler plate code when accessing and using infrastructure APIs (jdbc, jpa, jws, ldap, …), spring-ws offers as well a so called WebServiceTemplate, which allows clients for pretty easy and straightforward use of arbitrary WebServices.

the simplest way to use WebServiceTemplate is to extend from WebServiceGatewaySupport and use it via getWebServiceTemplate():

public class SimpleWebServiceClient extends WebServiceGatewaySupport {
    ...
    public void callWebService(){
        ...
        getWebServiceTemplate().send... // appropriate send-method out of the template toolset
    }
}

of course you can configure the template within springs application context, i.e. setting marshaller and unmarshaller or providing a defaultURI of a WebService you want to call.

<bean id="client" class="org.sample.ws.SimpleWebServiceClient">
    <property name="defaultUri" value="http://servicehost/serviceapp/ws/simpleservice/"/>
    <property name="marshaller" ref="castorMarshaller" />
    <property name="unmarshaller" ref="castorUnMarshaller" />
    ...
</bean>

that’s it in essence – it’s just simple as that (the various ways of configuring and using WebServiceTemplate aren’t subject to this entry, but may follow in some subsequent posts).

now if you use WebServiceTemplate in the above (default) way, a call to the WebService will go straight to the configured URI, using SOAP over http. if your client sits behind a http proxy (which isn’t unusual in a companies network), the call will never arrive on it’s direct way and you’ll end up with a connection timeout.

proxy settings

so what to do? how to teach the client that he has to make a little detour?
of course, when using SOAP over http, WebServiceTemplate will delegate some of it’s work to HttpUrlConnection (which will be wrapped indirectly within a so called WebServiceConnection).
HttpUrlConnection itself will obtain information about a given http proxy by inspecting some system properties. first of all, the property proxySet have to be set to value true. given that, you’ll have to provide the hostname and port of your http proxy – setting the properties proxyHost and proxyPort. this could be done in a programatic way by accessing the system properties and putting the required entries:

Properties systemProps = System.getProperties();
systemProps.put("proxySet", "true");
systemProps.put("proxyHost", "companiesProxy");
systemProps.put("proxyPort", "8080");

now your client call will take the detour over the given proxy.

authentification

there may be one last obstacle, that is if your proxy claims for authentification, so that the client has to identify himself to the proxy server.
as said, WebServiceTemplate will delegate to HttpUrlConnection, on which you could set an appropriate RequestProperty.
for instance, if your http proxy uses basic authentification, you could set the following RequestProperty:

...
sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
String encodedUserPwd = encoder.encode("myName:myPasswd".getBytes());
urlConnection.setRequestProperty("Authorization", "Basic " + encodedUserPwd);

but how to acquire access to the underlying HttpUrlConnection? short answer – there is no direct way.
ok, and here’s the long answer: one way to access further information about the currently used environment is to access a so called TransportContext.

TransportContext

an instance of a TransportContext can be obtained via a TransportContextHolder, which holds the current TransportContext in a ThreadLocal and provides a type safe getter and setter. beware, the current TransportContext isn’t initialized before calling one of WebServiceTemplates send method:

public void callWebService(){
    ...
    TransportContext transportContext = TransportContextHolder.getTransportContext();  // null
    getWebServiceTemplate().send... // appropriate send-method out of the template toolset
}

in order to get the chance of refering to TransportContext after the send method was called, you could implement a WebServiceMessageCallback:

class MyWebServiceMessageCallback implements WebServiceMessageCallback{
    public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
        TransportContext transportContext = TransportContextHolder.getTransportContext();
        WebServiceConnection connection = transportContext.getConnection();
    }
}
...
public void callWebService(){
    ...
    getWebServiceTemplate().sendSourceAndReceive(
        payloadSource, new MyWebServiceMessageCallback(), new MySourceExtractor() );
}

As you can see, TransportContext gives you access to the underlying WebServiceConnection which wrapps – in our case – indirectly our needed HttpUrlConnection. Unfortunately the interface of a WebServiceConnection won’t give you further access to it’s implementation details (because a WebServiceConnection could also be based on another transport protocoll!), so this is a one-way street.

Authenticator

With JDK 1.2, there’s java.netAuthenticator for passing credentials, when needed. a look into the pending javadoc informs, that ‘Authenticator represents an object that knows how to obtain authentication for a network connection‘.
There’s one important method that will provide information about the needed credentials, that is getPasswordAuthentication(). it’s easy to come up with an own version of Authenticator, that will handle our username and password, simply by overriding that method:

public class SimpleAuthenticator extends Authenticator{
    private String username, password;

    public SimpleAuthenticator(String username,String password){
        this.username = username;
        this.password = password;
    }

    protected PasswordAuthentication getPasswordAuthentication(){
        return new PasswordAuthentication(username,password.toCharArray());
    }
}

now we can set our credentials in a programatic way, to pass the needed information to our proxy for authentification:

Authenticator.setDefault(new SimpleAuthenticator("myUsername", "myPasswd" ));

conclusion

As you can see, spring ws is completely agnostic to the issue of http proxying.
and this is good so – it’s a concern that’s completely orthogonal to the concerns of calling a web service. in the case of SOAP over http you only have to provide information to the surrounding environment that will be used by the underlying network classes that spring ws relies on.

this is good news, because that means, that this solution isn’t limited to spring ws but appropriate to all kind of solutions under similar conditions.

9 Responses to “How to call a WebService with Spring-WS through a Proxy”

  1. Markus Says:

    Good starter for attaching WS to Spring .. thx!

    Btw:
    Congratulation to the relocation of your blog. I will adjust my Blogroll links asap.

  2. Tila Nguyen Says:

    Hi…Man i just love your blog, keep the cool posts comin..holy Tuesday . Tila Nguyen

  3. napyfab:blog» Blog Archive » links for 2007-11-27 Says:

    […] How to call a WebService with Spring-WS through a Proxy « brain driven development (tags: spring-ws spring java proxy webservice programming development guide tutorial) […]

  4. Dirk Says:

    Hi!

    Is it possible to set the proxy per connection, or per Thread. I have several outgoing connections, but only few of them should go through the proxy.

    Regards,
    Dirk

  5. Nik Says:

    Hi,

    What if the operations in the webservice returns java bean? (which is described in the WSDL as well). Is there a tool to generate classes from Javabean… and how to fetch the javabean from getWebServiceTemplate().send… method..

    Regards,
    Nik

  6. Nik Says:

    Hi,

    What if the operations in the webservice returns java bean? (which is described in the WSDL as well). Is there a tool to generate javabean classes from WSDL… and how to fetch the javabean from getWebServiceTemplate().send… method..

    (writing above message again – got a word wrong)

    I got the answer for the 1st part.. I am using the JAXB XJC tool.

    WSDL has many methods described for the web service. How to invoke these methods? Is it from the getWebServiceTemplate().send… only?

    Regards,
    Nik

  7. onebyteatatime Says:

    Guys,

    If you want to achieve setting proxy per connection, refer to http://onebyteatatime.wordpress.com/2009/04/08/spring-web-service-call-using-proxy-per-connection/

    hope that helps.

    ~srs

  8. Vijayakumar Says:

    Is it possible for you to provide a working exaple for this. Thank you.

  9. Francine Says:

    Skype has established its website-structured client beta on the entire world, after launching it extensively within the United states and U.K.
    before this four weeks. Skype for Website also now can handle Chromebook and Linux for
    instant text messaging communication (no video and voice yet,
    those need a plug-in installation).

    The expansion in the beta provides help for a longer list of spoken languages
    to help you strengthen that worldwide functionality


Leave a comment