[SWS-464] The use of WS Addressing results in malformed SOAP messages Created: 15/Dec/08  Updated: 04/May/12  Resolved: 16/Dec/08

Status: Closed
Project: Spring Web Services
Component/s: Core
Affects Version/s: 1.5.5
Fix Version/s: 1.5.6

Type: Bug Priority: Critical
Reporter: Oleg Kalnichevski Assignee: Arjen Poutsma
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

When WS Addressing is being used the Axiom message factory appears to produce malformed SOAP messages (details to follow)



 Comments   
Comment by Oleg Kalnichevski [ 15/Dec/08 ]

Axiom message factory appears to produce malformed messages. For instance, the problem can be triggered by the use of Web Addressing (see example below). The wsa name space declaration is missing in wsa:Action and wsa:MessageID header elements. Moreover, ideally the wsa namespace should be declared in the soapenv:Header. Please note at the same time the fault body seems sane.

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Header>
<wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" soapenv:mustUnderstand="true">xxxxxxxxxx</wsa:To>
<wsa:Action>xxxxxxxxxxxxxxxxxxxxxxxxx</wsa:Action>
<wsa:MessageID>urn:uuid:cf9f8e79-9226-4237-b014-bf431778ddab</wsa:MessageID>
</soapenv:Header>
<soapenv:Body>
<soapenv:Fault xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
<soapenv:Code>
<soapenv:Value>soapenv:Sender</soapenv:Value>
<soapenv:Subcode>
<soapenv:Value>wsa:MessageInformationHeaderRequired</soapenv:Value>
</soapenv:Subcode>
</soapenv:Code>
<soapenv:Reason>
<soapenv:Text xmlns:lang="en">A required message information header, To, MessageID, or Action, is not present.</soapenv:Text>
</soapenv:Reason>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>

Comment by Oleg Kalnichevski [ 15/Dec/08 ]

While admittedly this does look like a bug in Axiom, I think AxiomSoapHeader#addHeaderElement should register the namespace of the name passed as a parameter the same way the AxiomSoap12Fault#setText does.

I managed to work the problem around by replacing the code of AxiomSoapHeader#addHeaderElement method with the follwing one

public SoapHeaderElement addHeaderElement(QName name) {
try {
OMNamespace namespace = null;
String prefix = QNameUtils.getPrefix(name);
if (StringUtils.hasLength(name.getNamespaceURI()) && StringUtils.hasLength(prefix))

{ namespace = getAxiomHeader().findNamespaceURI(prefix); }

else if (StringUtils.hasLength(name.getNamespaceURI())) {
namespace = getAxiomHeader().findNamespace(name.getNamespaceURI(), null);
if (namespace == null)

{ throw new IllegalArgumentException("Could not resolve namespace of code [" + name + "]"); }

name = QNameUtils.createQName(name.getNamespaceURI(), name.getLocalPart(), namespace.getPrefix());
}
if (namespace == null)

{ namespace = getAxiomHeader().declareNamespace(name.getNamespaceURI(), QNameUtils.getPrefix(name)); }

SOAPHeaderBlock axiomHeaderBlock = getAxiomHeader().addHeaderBlock(name.getLocalPart(), namespace);
return new AxiomSoapHeaderElement(axiomHeaderBlock, getAxiomFactory());
}
catch (OMException ex)

{ throw new AxiomSoapHeaderException(ex); }

}

Comment by Arjen Poutsma [ 15/Dec/08 ]

I am not so sure about your proposed fix. For one thing, the following code fails with an IllegalArgumentException:

String namespace = "http://springframework.org/spring-ws";
QName headerName1 = new QName(namespace, "header1");
QName headerName2 = new QName(namespace, "header2");

SoapHeaderElement headerElement1 = soapHeader.addHeaderElement(headerName1);
SoapHeaderElement headerElement2 = soapHeader.addHeaderElement(headerName2);

I am working on another fix.

Comment by Arjen Poutsma [ 16/Dec/08 ]

I'm afraid I can't reproduce this. The following, which is what WS-Addressing does internally:

SoapMessageFactory messageFactory = new AxiomSoapMessageFactory();
SoapMessage message = (SoapMessage) messageFactory.createWebServiceMessage();
 
AddressingVersion version = new Addressing10();
 
MessageAddressingProperties map = new MessageAddressingProperties(new URI("http://springframework/to"),
        new EndpointReference(new URI("http://springframework/from")),
        new EndpointReference(new URI("http://springframework/replyTo")),
        new EndpointReference(new URI("http://springframework/faultTo")),
        new URI("http://springframework/action"),
        new URI("http://springframework/messageId"));
version.addAddressingHeaders(message, map);
 
message.writeTo(System.out);

ends up with:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsa:To xmlns:wsa="http://www.w3.org/2005/08/addressing" soapenv:mustUnderstand="1">http://springframework/to
</wsa:To>
<wsa:From xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>http://springframework/from</wsa:Address>
</wsa:From>
<wsa:ReplyTo xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>http://springframework/replyTo</wsa:Address>
</wsa:ReplyTo>
<wsa:FaultTo xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>http://springframework/faultTo</wsa:Address>
</wsa:FaultTo>
<wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://springframework/action</wsa:Action>
<wsa:MessageID xmlns:wsa="http://www.w3.org/2005/08/addressing">http://springframework/messageId</wsa:MessageID>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>

What version of Axiom are you on? I'm using 1.2.7.

Comment by Oleg Kalnichevski [ 16/Dec/08 ]

Arjen,

With all due respect I think you were too hasty in dismissing the issue. I am using Axiom 1.2.8, which explains the difference in behaviour. And yes, the problem is still there.

(1) Spring WS is unusable with the latest release of Axiom, which, as I said, is likely to be the Axiom's fault in the first place, but it does not really change the fact.
(2) Spring WS produces SOAP messages that are unnecessarily verbose. What is the point of declaring WSA namespace five times instead of one?
(3) Spring WS's behaviour is inconsistent. It registers namespaces at the fault level (soapenv:Fault), but for some reason does not do the same at header level (soapenv:Header)

Moreover there is no way to customize the way Spring WS generates SOAP messages except for a wholesale fork of the entire AxiomSoap* class hierarchy.

Please consider re-opening the issue

Oleg

Comment by Arjen Poutsma [ 16/Dec/08 ]

With all due respect I think you were too hasty in dismissing the issue. I am using Axiom 1.2.8, which explains the difference in behaviour. And yes, the problem is still there.

Ok, I've reopened the issue.

(1) Spring WS is unusable with the latest release of Axiom, which, as I said, is likely to be the Axiom's fault in the first place, but it does not really change the fact.

The latest release I can find is 1.2.7 (http://repo2.maven.org/maven2/org/apache/ws/commons/axiom/axiom-api/), I am not sure where to get 1.2.8.

Could you try Axiom 1.2.7 and see if that works any better for you?

(2) Spring WS produces SOAP messages that are unnecessarily verbose. What is the point of declaring WSA namespace five times instead of one

True. I will fix it, and consider that the fix of this issue, if that's OK with you.

(3) Spring WS's behaviour is inconsistent. It registers namespaces at the fault level (soapenv:Fault), but for some reason does not do the same at header level (soapenv:Header)

This is actually Axiom doing it's thing. Whenever you call createSOAPFaultCode() on an Axiom SOAPFactory, it adds the namespace of the code at the fault level.

Moreover there is no way to customize the way Spring WS generates SOAP messages except for a wholesale fork of the entire AxiomSoap* class hierarchy.

You can always obtain a reference to the raw Axiom SOAPMessage object using getAxiomMessage(). You can manipulate that in any way you want to. I kept Spring-WS's the AxiomSoap* classes package private, because I cannot guarantee that the API will stay backwards compatible over time. In fact, changes in Axiom code already forced me to change the class hierarchy in the past.

Comment by Arjen Poutsma [ 16/Dec/08 ]

The duplicate namespace declarations are now gone. I've added a 'addNamespaceDeclaration()' method to SoapElement.

Comment by Oleg Kalnichevski [ 16/Dec/08 ]

Arjen,

I apologize for being such a mess. Of course, the version Axiom I am using is 1.2.7, not 1.2.8. Stupid me. It turned out I was also unable to reproduce the problem when running the test snippet locally. The problem is perfectly reproducible, though, when code is executed inside the WebLogic Server 9.2 MP1 container. In fact, the following bit is pretty sufficient for triggering the problem.

AxiomSoapMessageFactory messageFactory = new AxiomSoapMessageFactory();
SoapMessage message = (SoapMessage) messageFactory.createWebServiceMessage();

QName n1 = new QName("http://schemas.xmlsoap.org/ws/2004/08/addressing", "To", "wsa");
QName n2 = new QName("http://schemas.xmlsoap.org/ws/2004/08/addressing", "Action", "wsa");

SoapHeaderElement he1 = message.getEnvelope().getHeader().addHeaderElement(n1);
he1.setText("whatever");
SoapHeaderElement h2 = message.getEnvelope().getHeader().addHeaderElement(n2);

setText("whatever");

message.writeTo(System.out);

I am no longer sure whether this is an Axiom issue at all, or Axiom simply ends up picking up a different implementation of some standard API when run inside an WLS container.

Anyways, this issue has no longer anything to do with Spring WS

> True. I will fix it, and consider that the fix of this issue, if that's OK with you.

That would be perfectly fine with me.

> This is actually Axiom doing it's thing. Whenever you call createSOAPFaultCode() on an Axiom SOAPFactory, it adds the namespace
> of the code at the fault level

I believe there is also an explicit call to SOAPFault#declareNamespace in the AxiomSoap12Fault#setValueText. I think AxiomSoapHeader#addHeaderElement ought to behave similarly.

Thank you so much

Oleg

Comment by Arjen Poutsma [ 16/Dec/08 ]

One thing you could try is to swap the StAX implementation provided by BEA with Woodstox. This probably requires setting classloading to parent-last...

FYI: the WS-Addressing module currently spits out:

<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
        <wsa:To soapenv:mustUnderstand="1">http://springframework/to</wsa:To>
        <wsa:From>
            <wsa:Address>http://springframework/from</wsa:Address>
        </wsa:From>
        <wsa:ReplyTo>
            <wsa:Address>http://springframework/replyTo</wsa:Address>
        </wsa:ReplyTo>
        <wsa:FaultTo>
            <wsa:Address>http://springframework/faultTo</wsa:Address>
        </wsa:FaultTo>
        <wsa:Action>http://springframework/action</wsa:Action>
        <wsa:MessageID>http://springframework/messageId</wsa:MessageID>
    </soapenv:Header>
    <soapenv:Body/>
</soapenv:Envelope>

Comment by Arjen Poutsma [ 16/Dec/08 ]

Resolving as fixed.

Comment by Arjen Poutsma [ 04/May/12 ]

Closing old issues

Generated at Fri Dec 15 17:37:47 UTC 2017 using JIRA 6.4.14#64029-sha1:ae256fe0fbb912241490ff1cecfb323ea0905ca5.