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.
November 26, 2007 at 4:18 pm
Good starter for attaching WS to Spring .. thx!
Btw:
Congratulation to the relocation of your blog. I will adjust my Blogroll links asap.
November 27, 2007 at 8:37 am
Hi…Man i just love your blog, keep the cool posts comin..holy Tuesday . Tila Nguyen
November 27, 2007 at 11:28 pm
[…] 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) […]
October 16, 2008 at 7:25 am
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
November 10, 2008 at 9:59 am
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
November 10, 2008 at 12:33 pm
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
April 8, 2009 at 4:07 pm
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
October 29, 2012 at 10:19 am
Is it possible for you to provide a working exaple for this. Thank you.
June 26, 2017 at 11:01 am
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