Using WebServiceTemplate and HTTPClient to enable Webservice read timeout

I was tasked to implement read timeouts in my Spring webservices. I need to be able to implement this on dozens of webservices fairly easy and be maintainable. I also wanted to use Groovy Spring DSL for my bean declarations, and have my timeout configurable, and Integration testable.


I started with JaxWsPortProxyFactoryBean and this worked great

routingLookupService(org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean) {
    serviceInterface = "com.comcast.ivr.das.services.RoutingLookupServicePortType"
    wsdlDocumentUrl = ConfigurationHolder.config.routingLookupService.wsdlDocumentUrl
    namespaceUri = "http://services.das.ivr.comcast.com"
    serviceName = "RoutingLookupService"
    endpointAddress = ConfigurationHolder.config.routingLookupService.endpointAddress
    maintainSession = "false"
}

But I was not able to set a Read Timeout on the JaxWsPortProxyFactoryBean implementation.

I started reading this blog:
http://onebyteatatime.wordpress.com/2009/03/19/how-to-set-socket-timeout-using-spring-webservicetemplate/ and this helped get me in to correct direction.

1st I wanted to use Groovy Spring DSL instead of XML syntax, but after converting the applicationContext, I immediately ran into an issue with my JAXB generated Request Objects not having the correct @XmlRootElement annotations in it, so I needed to take a slighty different approach.

I did take some insight from this Blog:
http://javaandjava.blogspot.com/2008/12/using-jaxb-in-spring-maven-environment.html

and came up with this Groovy Spring DSL using WebServiceTemplate

    routingLookupService(org.springframework.ws.client.core.WebServiceTemplate) {
        messageSenders = [ref("routingLookupHttpSender")]
        marshaller = ref("marshaller")
        unmarshaller = ref("marshaller")
        messageFactory = ref("axiomMessageFactory")
        defaultUri = ConfigurationHolder.config.routingLookupService.endpointAddress
    }

    routingLookupHttpClient(org.apache.commons.httpclient.HttpClient){
        params = ref(
                httpParams(org.apache.commons.httpclient.params.HttpClientParams){
                    // Timeout in milliseconds: in this case 2 minutes (120 000)
                    soTimeout = ConfigurationHolder.config.routingLookupService.timeout
                }
        )
    }
    routingLookupHttpSender(org.springframework.ws.transport.http.CommonsHttpMessageSender,
            ref("routingLookupHttpClient")){
    }
    routingLookupServiceClient(com.comcast.ivr.das.domain.routinglookup.xsd.RoutingLookupServiceClient){
        messageSenders = [ref("routingLookupHttpSender")]
    }

    //--- Common Webservices Beans ---//
    messageFactory(org.springframework.ws.soap.saaj.SaajSoapMessageFactory)
    axiomMessageFactory(org.springframework.ws.soap.axiom.AxiomSoapMessageFactory){
        payloadCaching = "true"
        soapVersion = org.springframework.ws.soap.SoapVersion.SOAP_12
    }

    marshaller(org.springframework.oxm.jaxb.Jaxb2Marshaller){
        contextPaths = ["com.comcast.ivr.das.services"]
        marshallerProperties = ["jaxb.formatted.output": true]
    }

In my RoutingLookupClient, I then extended WebServiceGatewaySupport so that I could…

public class RoutingLookupServiceClient extends WebServiceGatewaySupport {

    @Resource
    private WebServiceTemplate routingLookupService;

    /**
     * Get UIVR Lookup Routing
     * com.comcast.ivr.das.services.UivrLookupRoutingResponse
     *
     * @param request             {@link UivrRoutingLookupRequest}
     * @param attributeProperties {@link List<AttributeProperty>}
     * @return {@link RoutingLookupResponse}
     * @throws RoutingLookupServiceClientException
     *          for any Webservice Fault
     */
    public RoutingLookupResponse uivrLookupRouting(UivrRoutingLookupRequest request, List<AttributeProperty> attributeProperties)
            throws RoutingLookupServiceClientException {
        try {
            (request.getAttributePropertyList()).addAll(attributeProperties);

            final UivrLookupRouting uivrLookupRouting = new ObjectFactory().createUivrLookupRouting();

            uivrLookupRouting.setRoutingLookupRequest(request);

            return ((UivrLookupRoutingResponse) routingLookupService.marshalSendAndReceive(uivrLookupRouting, new WebServiceMessageCallback() {
                public void doWithMessage(WebServiceMessage webServiceMessage) throws IOException, TransformerException {
                    ((AxiomSoapMessage) webServiceMessage).setSoapAction(routingLookupService.getDefaultUri());
                }
            })).getReturn();
        } catch (org.springframework.ws.soap.client.SoapFaultClientException e) {
            throw new RoutingLookupServiceClientException();
        } catch (WebServiceIOException e) {
            throw new RoutingLookupServiceClientException();
        }
    }

And my Integration JUnit test to simulate a timeout:

    public void testRoutingLookupServiceClientTimeout(){

        try{
            routingLookupHttpSender.readTimeout = 2

            def RoutingLookupResponse routingLookupResponse = routingLookupServiceClient.uivrLookupRouting(request, attributeProperties);
            fail()
        }
        catch(RoutingLookupServiceClientException e){
            println("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^")
            println(e)
            assertTrue(true)
        }
    }

Next Steps

I have dozens of Webservices to create, and each will have their own timeout. The 1st thing I will work on is making routingLookupHttpClient and routingLookupHttpSender inner classes to simplify my namespace and number of beans I have to create for each new service.

conclusion

I think using the best of breed WebServiceTemplate as well as XXX allowed me to easily create webservice read timeouts and made testing very easy.

VN:F [1.9.1_1087]
Rating: 6.3/10 (3 votes cast)
VN:F [1.9.1_1087]
Rating: -1 (from 1 vote)
Using WebServiceTemplate and HTTPClient to enable Webservice read timeout, 6.3 out of 10 based on 3 ratings
  • Share/Bookmark

This entry was posted on Friday, April 9th, 2010 at 8:29 am and is filed under Grails-Groovy, Java-JavaEE-J2EE, Springframework. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

One Response to “Using WebServiceTemplate and HTTPClient to enable Webservice read timeout”

  1. Tweets that mention Using WebServiceTemplate and HTTPClient to enable Webservice read timeout | BASE Logic, Inc. -- Topsy.com Says:

    [...] This post was mentioned on Twitter by Mick Knutson. Mick Knutson said: Using WebServiceTemplate and HTTPClient to enable Webservice read timeout: I was tasked to implement read timeouts… http://bit.ly/bLyZrw [...]

Leave a Reply

You must be logged in to post a comment.