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.

Mick Knutson

Java, JavaEE, J2EE, WebLogic, WebSphere, JBoss, Tomcat, Oracle, Spring, Maven, Architecture, Design, Mentoring, Instructor and Agile Consulting. http://www.baselogic.com/blog/resume

View all posts

Java / JavaEE / Spring Boot Channel

BLiNC Supporters

BLiNC Adsense

Archives

Newsletter