How to set socket timeout using Spring WebServiceTemplate?

If you are using Spring for web services, there is a high probability that you have one of your classes extending WebServiceGatewaySupport class provided by Spring. This class has a method getWebServiceTemplate() that returns a WebServiceTemplate class on which you can invoke your requests to send and receive http requests. Typically, your code would look like:

public class RequestSender extends WebServiceGatewaySupport {
...
...
public void send(SomeWebServiceRequest request) {
    SomeWebServiceResponse response = getWebServiceTemplate().marshalSendAndReceive(request);
}
...
...
}

Now, what if the server takes too long to respond? In that case, you shall receive a SocketTimeoutException. There is a way, though not direct, to set timeout using WebServiceTemplate so that your request does not timeout due to slower server response. Here is how you can do it ALL WITHIN SPRING CONTEXT. All you need is commons-httpclient. Assuming you are using maven, first you need to include a dependency on commons-httpclient as shown below:

        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>

Including dependency above gives you access to HttpClient() class that we will use to set timeout. Once we have HttpClient with timeout set we shall inject this onto CommonsHttpMessageSender. It is this message sender that we are then going to inject onto WebServiceTemplate. Everything done via spring context config shown below:

...
...

<!-- Here is a relevant section of Spring Context -->
    <bean id="reqSender" class="mypackage.RequestSender">
       <property name="messageFactory">
         <bean class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
       </property>
       <property name="messageSenders">
         <list>
            <ref bean="httpSender" />
         </list>
       </property>
       <property name="marshaller" ref="myMarshaller" />
       <property name="unmarshaller" ref="myMarshaller" />
       <property name="defaultUri" value="http://webservice-url/deployed/at/some/server" />
    </bean>

    <bean id="httpParams" class="org.apache.commons.httpclient.params.HttpClientParams">
      <!-- Timeout in milliseconds: in this case 2 minutes -->
      <property name="soTimeout" value="120000" />
    </bean>

    <bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
      <property name="params" ref="httpParams" />
    </bean>

    <bean id="httpSender" class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
      <constructor-arg>
        <ref bean="httpClient"/>
      </constructor-arg>
    </bean>    

    <bean id="myMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller" >
      <property name="contextPath" value="path_to_directory_with_jaxb_xml_generated_classes"/>
    </bean>
...
...

Well, hope that saves you hours of frustration trying to figure out how to set timeout in order to handle slow server response.

~srs

Where in Spring is Jaxb2Marshaller?

I just answered this question for myself after some frustration reading through Spring documentation. I was trying to use Jaxb2Marshaller implementation provided by Spring. Had a real hard time finding where exactly this class is located in Spring Jars.

Spring WS Tutorial – Chapter 8

gives a fair idea to the reader about marshalling, unmarshalling and how to inject marshallers into WebServiceTemplate etc. But it does not say where Jaxb2Marshaller is. I use Maven for building my project and in Maven you must include artifact dependency:

        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-oxm-tiger</artifactId>
            <version>1.5.4</version>
        </dependency>

in order to use Spring WS Jaxb2Marshaller. If you are using Jaxb1Marshaller you would be ok with just plain “spring-ws-core” artifact as your dependency. Hope this saves some frustration to some of my readers trying to find out the answer to the very question, I made into a title of this post!

~srs