JAX-WS, wsimport, and the error “MustUnderstand headers … not understood”

Following the previous adventure surrounding collision in the object factory class, this time around we take it a step further. Instead of simply using xjc command from JAXB and marshall/unmarshall elements into the SOAP envelope, we thought lets use wsimport against the WSDL instead. Again, wsimport is part of standard JDK.

The tool wsimport also makes use of xjc and therefore the collision issue also occurred. Thankfully, we can specify the binding (-b) argument with wsimport as well. Even better, use the following maven plugin:

<plugin>
    <groupId>org.jvnet.jax-ws-commons</groupId>
    <artifactId>jaxws-maven-plugin</artifactId>
    <version>2.1</version>
    <executions>
        <execution>
            <goals>
                <goal>wsimport</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <target>2.1</target>
        <extension>true</extension>
        <bindingDirectory>src/main/resources</bindingDirectory>
        <bindingFiles>
            <bindingFile>bindings.xjb</bindingFile>
        </bindingFiles>
        <wsdlDirectory>src/main/resources</wsdlDirectory>
        <wsdlFiles>
            <wsdlFile>schemas.ppsr.gov.au.2011.04.services.wsdl</wsdlFile>
        </wsdlFiles>
    </configuration>
</plugin>

All is well and good now.

When we actually hit the end point, the following error is thrown:

27/03/2012 6:40:20 PM com.sun.xml.internal.ws.protocol.soap.MUTube getMisUnderstoodHeaders
INFO: Element not understood={http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security
Exception: MustUnderstand headers:[{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] are not understood

The interesting thing is that invoking using soapUI, all worked okay, and the following response returned:


<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header>
        <wsse:Security
            xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
            S:mustUnderstand="1">
            <wsse:UsernameToken 
                xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                wsu:Id="UsernameToken-1">
                <wsse:Username><!-- omitted --></wsse:Username>
                <wsse:Password 
                    Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
                    <!-- omitted -->
                </wsse:Password>
                <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
                    <!-- omitted -->
                </wsse:Nonce>
                <wsu:Created>2012-03-27T07:40:19.628Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </S:Header>
    <S:Body>
        <ns2:PingRequestMessage
            xmlns="http://schemas.ppsr.gov.au/2011/04/data"
            xmlns:ns2="http://schemas.ppsr.gov.au/2011/04/services"
            xmlns:ns3="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
            xmlns:ns4="http://schemas.ppsr.gov.au/faults" />
    </S:Body>
</S:Envelope>

After further reading, we discover it’s mostly related to the mustUnderstand and the way we use javax.xml.ws.handler.soap.SOAPHandler (White 2010). Reading javadoc itself is not enough, since the getHeaders() method simply says “Gets the header blocks that can be processed by this Handler instance” (Oracle 2011).

Therefore, to resolve this issue, our handler must understand the response, and that’s done by “handling” the response as follows:

PPSRSOAPMessageHandler

package com.wordpress.dwuysan;

import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class PPSRSOApMessageHandler implements SOAPHandler<SOAPMessageContext> {
    // ... the rest of the code omitted

    @Override
    public Set<QName> getHeaders() {
        final QName securityHeader = new QName(
            "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
            "Security",
            "wsse");

        // ... "understand" the response, very complex logic goes here
        // ... "understand" the response, very complex logic goes here
        // ... "understand" the response, very complex logic goes here

        final HashSet headers = new HashSet();
        headers.add(securityHeader);

        // notify the runtime that this is handled
        return headers;
    }

    // ... the rest of the code omitted
}

References:
Oracle, 2011, SOAPHandler (Java EE 6), accessed 02 April 2012.

White, J, 2010, Working with Headers in JAX-WS SOAPHandlers, accessed 02 April 2012.

Advertisements

[ERROR] Two declarations cause a collision in the ObjectFactory class

This issue, and its workaround, has been identified by the Unofficial JAXB Guide – Dealing with errors (Project JAXB 2012).

When one of my colleagues and I faced this issue, we still had to spend some amount of time trying to “understand” why, and how to fix it. I thought I’ll share some examples and findings so that in the future people can easily resolve it.

To start with, the error occur because the same name between a TYPE and an ELEMENT. Please refer to the following XML snippet. (The example that is used here is based on the XSD obtained from Personal Property Securities Register).

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://schemas.ppsr.gov.au/2011/04/data" 
    elementFormDefault="qualified" 
    targetNamespace="http://schemas.ppsr.gov.au/2011/04/data" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <!-- The rest of the code removed -->

    <xs:complexType name="GrantorOrganisation">
        <!-- Content removed -->
    </xs:complexType>
    <xs:element name="GrantorOrganisation"
        nillable="true" type="tns:GrantorOrganisation" />

    <!-- The rest of the code removed -->
</xs:schema>

Notice that the GrantorOrganisation is used as the name for both name and type, hence the collision.

To resolve this, use the JAXB binding and modify the objectFactory method name. Please refer to the bindings.xjb below:

<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
          xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
          xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
          xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd" version="2.1">
    <globalBindings>
        <serializable uid="1" />
    </globalBindings>
    <bindings schemaLocation="schemas.ppsr.gov.au.2011.04.data.xsd">
        <bindings node=".//xs:element[@name='GrantorOrganisation']">
            <factoryMethod name="GrantorOrganisationElement" />
        </bindings>
        <!-- rest of the code remove, need to do it for every collision -->
    </bindings>
</bindings>

Some findings:

  • I was under impression that since it is collision, I can also bind the type instead. So the node will be node=".//xs:complexType[@name='GrantorOrganisation']". That did NOT work.
  • Since the node argument has the prefix xs:, also need to add the xs in the declaration of my binding file (Even thought I did not use it anywhere else).

P.S. Many thanks to George Gao for sharing the solution.

References:

Project JAXB, 2012, ‘Unofficial JAXB Guide – Dealing with errors’, accessed 08 March 2012.

Personal Property Securities Register, 2012, Accessing the PPSR Business to Government (B2G) Channel, accessed 08 March 2012.