WebServiceTemplate and Timeout
Spring WS 1.0 API doesn’t support timeout for web service invocations. This feature can be achieved by using Jakarta Commons HttpClient. SSL timeout requires moreover the use of Not Yet Commons SSL (in fact, this product is just only an extension of JSSE).
Below a sample class and a sample application context configuration.
import java.io.IOException;
import java.io.File;
// commons-httpclient
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
// not-yet-commons-ssl
import org.apache.commons.ssl.HttpSecureProtocol;
import org.apache.commons.ssl.KeyMaterial;
import org.apache.commons.ssl.TrustMaterial;
// spring ws
import org.springframework.oxm.xmlbeans.XmlBeansMarshaller;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.transport.http.CommonsHttpMessageSender;
public class SpringWSClient extends WebServiceGatewaySupport {
// Marshalling
private XmlBeansMarshaller xmlBeansMarshaller;
// Truststore
private String pathToJksTrustStore;
private String jksTrustStorePassword;
// Keystore
private String pathToJksKeyStore;
private String jksKeyStorePassword;
// Timeout
private int timeOutMs;
// SSL Port
private static final int SSL_PORT = 443;
// Default constructor
public SpringWSClient(XmlBeansMarshaller xmlBeansMarshaller) {
this.xmlBeansMarshaller = xmlBeansMarshaller;
}
// Do WS invocation
public Object callWs(Object input) {
// SSL connection?
if (getWebServiceTemplate().getDefaultUri().toLowerCase().startsWith(
"https")) {
sslProtocolInit();
}
// Marshalling stuff (XMLBeans)
WebServiceTemplate wst = getWebServiceTemplate();
wst.setMarshaller(getXmlBeansMarshaller());
wst.setUnmarshaller(getXmlBeansMarshaller());
// Timeout (commons-httpclient)
HttpClient client = new HttpClient();
client.getParams().setSoTimeout(new Integer(getTimeOutMs()));
CommonsHttpMessageSender messageSender = new CommonsHttpMessageSender(
client);
wst.setMessageSender(messageSender);
// Invocation
Object result = wst.marshalSendAndReceive(input,
new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message)
throws IOException {
// ...
}
});
return result;
}
// SSL protocol (not-yet-commons-ssl)
protected void sslProtocolInit() {
HttpSecureProtocol protocolSocketFactory;
try {
protocolSocketFactory = new HttpSecureProtocol();
File jksTrustStore = new File(pathToJksTrustStore);
TrustMaterial trustMaterial = new TrustMaterial(jksTrustStore,
jksTrustStorePassword.toCharArray());
protocolSocketFactory.addTrustMaterial(trustMaterial);
// No host name verification
protocolSocketFactory.setCheckHostname(false);
File jksKeyStore = new File(pathToJksKeyStore);
KeyMaterial key = new KeyMaterial(jksKeyStore, jksKeyStorePassword
.toCharArray());
protocolSocketFactory.setKeyMaterial(key);
// Timeout
protocolSocketFactory.setConnectTimeout(getTimeOutMs());
// Register protocol
Protocol protocol = new Protocol("https",
(ProtocolSocketFactory) protocolSocketFactory, SSL_PORT);
Protocol.registerProtocol("https", protocol);
} catch (Exception e) {
e.printStackTrace();
}
}
public XmlBeansMarshaller getXmlBeansMarshaller() {
return xmlBeansMarshaller;
}
public void setXmlBeansMarshaller(XmlBeansMarshaller xmlBeansMarshaller) {
this.xmlBeansMarshaller = xmlBeansMarshaller;
}
public int getTimeOutMs() {
return timeOutMs;
}
public void setTimeOutMs(int timeOutMs) {
this.timeOutMs = timeOutMs;
}
public String getPathToJksFile() {
return pathToJksFile;
}
public void setPathToJksFile(String pathToJksFile) {
this.pathToJksFile = pathToJksFile;
}
public String getJksPassword() {
return jksPassword;
}
public void setJksPassword(String jksPassword) {
this.jksPassword = jksPassword;
}
}
<bean id="springWSClient" class="SpringWSClient">
<constructor -arg ref="xmlBeansMarshaller"/>
<property name="defaultUri" value="${ws.url}" />
<property name="pathToJksTrustStore" value="${trustStore.location}" />
<property name="jksTrustStorePassword" value="${trustStore.password}" />
<property name="pathToJksKeyStore" value="${keyStore.location}" />
<property name="jksKeyStorePassword" value="${keyStore.password}" />
<property name="timeOutMs" value="${ws.timeout}" />
</bean>
simple and clean illustration. thanks a lot. will give it a try today.
sridhar
March 3, 2009 at 3:11 pm