Search code examples
web-servicesspring-wsjboss6.xaxiomsaaj

Improve reading of web service responses at the client side by using AxiomSoapMessageFactory


We currently call SOAP web services which send back very big responses.

We use Spring-WS (using WebServiceTemplate), JAX-WS client while invoking the web services and the application is run on Jboss EAP 6.0.

We also use SaajSoapMessageFactory currently. I read from forums that AxiomSoapMessageFactory should be used rather than SaajSoapMessageFactory (http://docs.spring.io/spring-ws/site/reference/html/common.html) to improve reading performance.

I made the following modification:

Replaced

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"> 
        <property name="soapVersion">
            <util:constant static-field="org.springframework.ws.soap.SoapVersion.SOAP_11" />
        </property>
    </bean>

by

 <bean id="messageFactory" class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
        <property name="payloadCaching" value="true"/>
    </bean>

This change worked fine as expected. However, the link which I had mentioned above suggested to set do the following :

 <property name="payloadCaching" value="false"/>

After I set this option and when the web service was invoked, I get the below exception :

org.springframework.ws.soap.axiom.AxiomSoapBodyException: Could not access envelope: null; nested exception is org.apache.axiom.om.NodeUnavailableException: org.springframework.ws.soap.axiom.AxiomSoapBodyException: Could not access envelope: null; nested exception is org.apache.axiom.om.NodeUnavailableException
    at org.springframework.ws.soap.axiom.AxiomSoapEnvelope.getBody(AxiomSoapEnvelope.java:97) [:2.2.0.RELEASE]
    at org.springframework.ws.soap.AbstractSoapMessage.getSoapBody(AbstractSoapMessage.java:38) [:2.2.0.RELEASE]
    at org.springframework.ws.soap.AbstractSoapMessage.getPayloadSource(AbstractSoapMessage.java:50) [:2.2.0.RELEASE]
    at org.springframework.ws.support.MarshallingUtils.unmarshal(MarshallingUtils.java:55) [:2.2.0.RELEASE]
    at org.springframework.ws.client.core.WebServiceTemplate$3.extractData(WebServiceTemplate.java:413) [:2.2.0.RELEASE]
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:616) [:2.2.0.RELEASE]
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555) [:2.2.0.RELEASE]
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390) [:2.2.0.RELEASE]
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:383) [:2.2.0.RELEASE]
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:373) [:2.2.0.RELEASE]

Any ideas on why this error ? Have I missed changing any other option or is it the incompatibility of the library files that I have used.

Another question:


After commenting out my log4j entries related to og4j.logger.org.springframework.ws.client.MessageTracing, I was able to comsume the web service successfully. Also ran a performance test and found that for a test with 50 users concurrently accessing the web service (indirectly via a screen that in turn invokes the web service), the overall response time (moment the button is clicked to the moment the response from the web service is displayed back on the screen) reduced from ~ 27 secs to 22 secs -that's a good 5 second improvement over SaajSoapMessageFactory. However, when I ran a 100 user test, the response time increased by 2 secs and SaajSoapMessageFactory appears to be better in this case. Can someone explain the reason for this difference in performance despite AxiomSoapMessageFactory using streaming and avoiding building tree??


Solution

  • payloadCaching=false instructs Axiom not to build the object model tree for the payload. This is what enables the performance gain, but it also implies that the payload can only be accessed once. In older Axiom versions, an attempt to access the payload a second time will result in a somewhat obscure OMException. In the latests versions, it triggers a NodeUnavailableException which is documented in the Javadoc. As you noted in your comment, in your case the payload is consumed by the trace logging.