Uploaded image for project: 'Spring Web Services'
  1. Spring Web Services
  2. SWS-86

Stream closed before response read with WebServiceTemplate + Axis SAAJ Soap Messages

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 1.0 M3
    • Fix Version/s: 1.0 RC1
    • Component/s: Core
    • Labels:
      None
    • Environment:
      jdk 1.4
      Axis 1.4 (for SAAJ).
      Xerces 2.8.1
      Saxon 8.7

      Description

      http://forum.springframework.org/showthread.php?t=34306

      I'm converting an existing SAAJ client into a Spring-WS client. I got the following error when the template tries to check for the fault:

      org.springframework.ws.soap.saaj.SaajSoapEnvelopeE xception: Could not access envelope: org.xml.sax.SAXParseException: Premature end of file.; nested exception is javax.xml.soap.SOAPException: org.xml.sax.SAXParseException: Premature end of file.

      It appears that the messages are created lazily from the stream, but the stream is closed before that happens. I was able to work around the problem by forcing the message to be read in the readResponse method (using hasFault() in this case, there may be a better way):

      HttpUrlConnectionMessageSender webServiceMessageSender = new HttpUrlConnectionMessageSender() {
      protected void readResponse(HttpURLConnection connection, MessageContext messageContext) throws IOException {
      if (connection.getResponseCode() == HttpURLConnection.HTTP_NO_CONTENT || connection.getContentLength() == 0) {
      return;
      }
      TransportInputStream tis = null;
      try {
      tis = new HttpUrlConnectionTransportInputStream(connection);
      messageContext.readResponse(tis);
      /* workaround problem with lazy read - force message to be read before stream is closed */
      messageContext.getResponse().hasFault();
      }
      finally {
      if (tis != null) {
      tis.close();
      }
      }
      }
      };

      I'm using Java 1.4, Spring 1.0 M3, and my SAAJ implementation is Axis 1.4. I suspect the behaviour may not be evident for other SAAJ implementations.

      I've shown the HttpUrlConnectionMessageSender here but same problem and workaround applies for the commons http client one.

        Activity

        Hide
        bradh Brad Harvey added a comment -

        My message factory:

        <bean id="messageFactory"
        class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
        <constructor-arg>
        <bean class="org.apache.axis.soap.MessageFactoryImpl" />
        </constructor-arg>
        </bean>

        Show
        bradh Brad Harvey added a comment - My message factory: <bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"> <constructor-arg> <bean class="org.apache.axis.soap.MessageFactoryImpl" /> </constructor-arg> </bean>
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        Good catch. I'm afraid this issue has serious consequences.

        Currently, the WebServiceMessageSender closes the connection to the server as soon as possible. This does not work with lazy-loading SoapMessage implementations, such as Axis1 SAAJ, and Axis2 AXIOM. One solution would be to force the implementation to read the entire message, like you suggested, but then the effects of lazy-loading would be gone.

        A better solution would be to create a Connection abstraction, which is opened before the request message callback is invoked, so that the request message can be streamed to the server, and closed when a response callback is done with the message, so that the response message can be lazy loaded.

        Show
        arjen.poutsma Arjen Poutsma added a comment - Good catch. I'm afraid this issue has serious consequences. Currently, the WebServiceMessageSender closes the connection to the server as soon as possible. This does not work with lazy-loading SoapMessage implementations, such as Axis1 SAAJ, and Axis2 AXIOM. One solution would be to force the implementation to read the entire message, like you suggested, but then the effects of lazy-loading would be gone. A better solution would be to create a Connection abstraction, which is opened before the request message callback is invoked, so that the request message can be streamed to the server, and closed when a response callback is done with the message, so that the response message can be lazy loaded.
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        Fixed.

        Unfortunately, I had to change the interface of WebServiceTemplate in order to do so. Methods which return a Source could not be sustained, because the inputstream underlying the Source could already be closed. Instead, there is a SourceExtractor interface, which allows you to read from the source.

        Show
        arjen.poutsma Arjen Poutsma added a comment - Fixed. Unfortunately, I had to change the interface of WebServiceTemplate in order to do so. Methods which return a Source could not be sustained, because the inputstream underlying the Source could already be closed. Instead, there is a SourceExtractor interface, which allows you to read from the source.
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        Closing RC1 issues.

        Show
        arjen.poutsma Arjen Poutsma added a comment - Closing RC1 issues.

          People

          • Assignee:
            arjen.poutsma Arjen Poutsma
            Reporter:
            bradh Brad Harvey
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: