Left angle bracket removed when sending a SOAP message from Spring-WS client on Java7 to server on Java 6
Asked Answered
A

2

5

This has been really frustrating for me so I'll try explain what I know and don't now. Please make sure to see my updates at the bottom of the post.

First, we have a war that uses Spring-WS to process messages. We also have a client that uses WebServiceTemplate to send messages. We deploy on Tomcat 7.

In our current dev environment, the Tomcat 7 server is using JRE 6u24. Locally, I'm running the same version when I use the client to send a SOAP message. Everything works as expected.

When I make my local JRE 7u04, I get a 500 response and the server sees the following error:

[2012-05-05 20:19:13,179] DEBUG - org.springframework.web.servlet.FrameworkServlet.processRequest(671) | Could not complete request
org.springframework.ws.soap.saaj.SaajSoapEnvelopeException: Could not access envelope: Unable to create envelope from given source: ; nested exception is com.sun.xml.messaging.saaj.SOAPExceptionImpl: Unable to create envelope from given source:
        at org.springframework.ws.soap.saaj.SaajSoapMessage.getSaajVersion(SaajSoapMessage.java:260)
        at org.springframework.ws.soap.saaj.SaajSoapMessage.getImplementation(SaajSoapMessage.java:342)
        at org.springframework.ws.soap.saaj.SaajSoapMessage.<init>(SaajSoapMessage.java:117)
        at org.springframework.ws.soap.saaj.SaajSoapMessageFactory.createWebServiceMessage(SaajSoapMessageFactory.java:184)
        at org.springframework.ws.soap.saaj.SaajSoapMessageFactory.createWebServiceMessage(SaajSoapMessageFactory.java:58)
        at org.springframework.ws.transport.AbstractWebServiceConnection.receive(AbstractWebServiceConnection.java:90)
        at org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:86)
        at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:57)
        at org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:222)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:684)
        at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:471)
        at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:402)
        at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:329)
        at org.tuckey.web.filters.urlrewrite.NormalRewrittenUrl.doRewrite(NormalRewrittenUrl.java:195)
        at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:159)
        at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:141)
        at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:90)
        at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:417)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:964)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
Caused by: com.sun.xml.messaging.saaj.SOAPExceptionImpl: Unable to create envelope from given source:
        at com.sun.xml.messaging.saaj.soap.EnvelopeFactory.createEnvelope(EnvelopeFactory.java:127)
        at com.sun.xml.messaging.saaj.soap.ver1_2.SOAPPart1_2Impl.createEnvelopeFromSource(SOAPPart1_2Impl.java:84)
        at com.sun.xml.messaging.saaj.soap.SOAPPartImpl.getEnvelope(SOAPPartImpl.java:150)
        at org.springframework.ws.soap.saaj.support.SaajUtils.getSaajVersion(SaajUtils.java:155)
        at org.springframework.ws.soap.saaj.SaajSoapMessage.getSaajVersion(SaajSoapMessage.java:257)
        ... 39 more
Caused by: javax.xml.transform.TransformerException: org.xml.sax.SAXParseException: The markup in the document preceding the root element must be well-formed.
        at org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:501)
        at com.sun.xml.messaging.saaj.util.transform.EfficientStreamingTransformer.transform(EfficientStreamingTransformer.java:414)
        at com.sun.xml.messaging.saaj.soap.EnvelopeFactory.createEnvelope(EnvelopeFactory.java:118)
        ... 43 more
Caused by: org.xml.sax.SAXParseException: The markup in the document preceding the root element must be well-formed.
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1231)
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
        at org.xml.sax.helpers.XMLFilterImpl.parse(XMLFilterImpl.java:333)
        at org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:484)
        ... 45 more

I've went through a lot of potential issues. However, I think I've narrowed it down to being a SAAJ issue in some respect.

In the SaajSoapMessageFactory class for Spring-WS there is a method that begins with:

public SaajSoapMessage createWebServiceMessage(InputStream inputStream) throws IOException {
        MimeHeaders mimeHeaders = parseMimeHeaders(inputStream);
        try {
            inputStream = checkForUtf8ByteOrderMark(inputStream);
            SOAPMessage saajMessage = messageFactory.createMessage(mimeHeaders, inputStream);
            postProcess(saajMessage);
            return new SaajSoapMessage(saajMessage, langAttributeOnSoap11FaultString, messageFactory);
        }

When I send using the client with JRE 6, the inputStream AFTER the createMessage call begins like:

[60, 101, 110, 118, 58, 69, 110, 118, 101, 108, 111, 112, 101, 32, 120, 109, 108, 110, 115, 58, 101, 110, 118, 61, 34, 104, 116

Which converts to: <env:Envelope... etc.

However, when I send using the client with JRE 7, the inputStream after the createMessage call begins like:

[101, 110, 118, 58, 69, 110, 118, 101, 108, 111, 112, 101, 32, 120, 109, 108, 110, 115, 58, 101, 110, 118, 61, 34, 104, 116

As you can see the first byte, the left angle bracket, has gone missing. I have been trying to debug down into it but I lack the com.sun.xml.internal sources to really do much effectivey.

Also of note, in JRE 6, the PushbackInputStream AFTER the checkForUtf8ByteOrderMark call actually looks like the final byte array:

[60, 101, 110, 118, 58, 69, 110, 118, 101, 108, 111, 112, 101, 32, 120, 109, 108, 110, 115, 58, 101, 110, 118, 61, 34, 104, 116, etc

But when sending using JRE 7, it looks like this:

[60, 0, 0, 0, 0, 0, 0, 0, 0, etc

Now, the method itself seems to follow the same flow, verifying that there is no BOM and then putting back what it took off to verify it (at least, so it appears to me).

So, I have two questions:

1) Does anyone know what's going on? Is there anything here that's ringing a bell?

2) How can I get the source for those com.sun.xml.internal packages?

I should note, I can run this locally on Tomcat in Eclipse and not seem to have any issues, but I know there's some funky class loading stuff probably going on there.

Update 1:

I was able to associate some source to the code and got into this method in SOAPPart1_2Impl:

   public void setContent(Source source) throws SOAPException {
        try {
            if (source instanceof StreamSource) {
                InputStream is = ((StreamSource) source).getInputStream();
                Reader rdr = ((StreamSource) source).getReader();

                if (is != null) {
                    this.source = new JAXMStreamSource(is);
                } else if (rdr != null) {
                    this.source = new JAXMStreamSource(rdr);
                } else {
                    log.severe("SAAJ0544.soap.no.valid.reader.for.src");
                    throw new SOAPExceptionImpl("Source does not have a valid Reader or InputStream");
                }
            }

Now, it takes the first path of setting the InputStream. What's very interesting is that when this is done, source has a ByteInputStream that begins as such:

[60, 0, 0, 101, 110, 118, 58, 69, 110, 118, 101, 108, 111, 112, 101, 32, 120, 109, 108, 110, 115, 58, 101, etc

I'm very confused by this. I'll will try to figure out what exactly happens to those firs three characters -- maybe there is some side effect to the checkForUtf8ByteOrderMark method.

Update 2:

Okay, now I'm really getting somewhere. I looked into that JAXMStreamSource class and that leads to a ByteOutputStream class which has a method:

public void write(InputStream in) throws IOException {
    if (in instanceof ByteArrayInputStream) {
        int size = in.available();
        ensureCapacity(size);
        count += in.read(buf,count,size);
        return;
    }
    while(true) {
        int cap = buf.length-count;
        int sz = in.read(buf,count,cap);
        if(sz<0)    return;     // hit EOS

        count += sz;
        if(cap==sz)
            // the buffer filled up. double the buffer
            ensureCapacity(count);
    }
}

On the line "int sz = in.read(buf,count,cap);" is where the two zeros after the 60 gets added. I'm still trying to figure out why and why a client, of all things, using 1.7 could have possibly had this effect.

Anthropophagite answered 6/5, 2012 at 1:28 Comment(3)
you can get the source of the jdk from the openjdk project.Ruck
@Ruck I did visit this page download.java.net/openjdk/jdk6 and download the source there. However, I didn't find any of these internal classes, so perhaps that wasn't the right place? I did manage to find a number of these files online so I just made my own little source jar and associated it with my project. Not great, but passable.Anthropophagite
not all of the source files are in the main download. it's kind of annoying. you can run the included ant scripts to download some of the secondary bundles (jaxws, jaxb, etc).Ruck
A
4

Upgrading to 2.0.4.RELEASE somehow fixed this problem. The checkForUtf8ByteOrderMark method didn't change but something else must have changed as the stream coming in looked different after that.

Anthropophagite answered 6/5, 2012 at 19:48 Comment(1)
We had same issue. "spring-ws 2.0.2" webservice worked over http, but didn't work over https. Upgrading on spring-ws 2.0.4 solved our issue. Thanks a lotLondoner
C
3

maybe there is some side effect to the checkForUtf8ByteOrderMark method.

I think you might be right

https://jira.springsource.org/browse/SWS-750

Contrabandist answered 6/5, 2012 at 2:24 Comment(5)
I had seen that but after more investigating, I think not. I was a little confused as to what stream was being used, and it's actually the one in my update (sorry). So, the real issue now isn't that the 60 byte is missing, but that there's two 0 bytes in there. Thank you for trying to point me in a good direction, though.Anthropophagite
What Spring-WS version do you use by the way?Contrabandist
I'm currently using 2.0.2.RELEASE. I know 2.0.5 is the latest version but I'm not sure if/when I'll be able to move up.Anthropophagite
Actually, the more I delve, more I think it is indeed a side effect of that, haha. I'll have to extend that class or implement its interface and try some changes, I think. This has really made my mind twist.Anthropophagite
Yes, yes, yes! Because the buf pulled off what it did, there's code in the PushbackInputStream to first add the buffer, then read in bytes. So, it reads into those three bytes then reads the rest. It was indeed a side effect! You posting this here made me look over the chain of events again and that made me reexamine it just right. I'll have to look and see if 2.0.5 has a better version of this or not.Anthropophagite

© 2022 - 2024 — McMap. All rights reserved.