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.