The JWSDP 1.6 JAX-RPC framework does not give you out-of-the-box W3C Schema validation for the exchanged XML messages. This is a sad thing because explicit contracts are an important part of SOA, and adhering to these contracts improves interoperability and maintainability. It also makes programming easier if the interface definition and preconditions explicitly expressed in Schema are enforced. It doesn’t seem to be possible to switch on STAX parser validation in the mentioned framework. A JAX-RPC handler which validates each message is another way to achieve this goal.
It’s advisable to start the technical design of a Web Service with defining a (strict) XML schema. This contract-first (or design-by-contract) approach leads to strict, stable interfaces and is a clean way to allow developers on both the client and the server side to start implementing at the same time. Alternative approaches usually generate service contracts from a programmed implementation. In this case, if the implementation is (slightly) changed, or a different (version of the) framework is used, then the generation step should be repeated giving a possibly different interface. This break-of-contract requires all clients to update their implementation, which is obviously a bad thing. Another disvantage of the generation approach is pre- and postconditions staying as unmentioned as they are in the source language (you can’t express them first-class in Java or .NET).
As the JWSDP 1.6 JAX-RPC framework doesn’t seem to provide a method to switch on validation, we could implement this as a JAX-RPC handler. Like Servlet Filters allow you to filter HttpRequests and HttpResponses, JAX-RPC handlers allow you to filter incoming and outgoing SOAPMessages (DOM Elements). This handler can validate each incoming (and possibly outgoing) message to the contract.
The jaxp1.3 API (see usage jaxp1.3) makes Schema validation simple to implement. It’s included by default in Java 5, and as JWSDP 1.6 contains an implementation of jaxp1.3 you can also use in with jdk 1.4. The ValidationHandler would look something like this:
package mypackage.ws.validation.ValidationHandler;
import javax.xml.rpc.handler.*;
import java.util.*;
import javax.xml.soap.*;
import org.w3c.dom.*;
public class ValidationHandler extends GenericHandler
{
public boolean handleRequest(MessageContext context)
{
SOAPBody body = ((SOAPMessageContext) context).getMessage()
.getSOAPPart().getEnvelope().getBody();
Iterator it = body.getChildElements();
while ( it.hasNext() )
{
Element el = (Element) it.next();
validate(el); // does the real XML validation,
// not shown here for abbreviation
}
}
}
This handler can be used manually, but by adding it to config.xml it can be generated into the web service stub. The config file would look like:
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<wsdl location="wsdlFile.wsdl" packageName="mypackage.ws.server">
....
<handlerChains>
<chain runAt="server">
<handler
className="mypackage.ws.validation.ValidationHandler" />
</chain>
</handlerChains>
</wsdl>
</configuration>
My implementation (validation.zip) of this strategy also takes into account the fastinfoset bug that seems to pop up when you start using handlers. Feel free to use the code as you like as long as you don’t hold me liable.
If you use jdk1.4 and add the jaxp libraries from jwsdp to your classpath, don’t forget to register them as endorsed libraries at runtime! Otherwise you’re still using the ancient jaxp implementation contained in the jdk1.4 boot libraries. This overriding of system libraries can be done by adding jvm options -Djava.endorsed.dirs=${jwsdp_home}/jaxp/lib;
${jwsdp_home}/jaxp/lib/endorsed, assuming the paths of the 5 jaxp1.3 jars you’ve added to the classpath each start with ${jwsdp_home}/jaxp/lib.
See for more information: the Endorsed Standards Override Mechanism.
Symptoms of skipping the step above are errors like:
- class “org.w3c.dom.ls.LSException”’s signer information does not match signer information of other classes in the same package
- Missing <method(args)> from a jaxp class, e.g.
java.lang.NoSuchMethodError: javax.xml.parsers.SAXParserFactory.getSchema(), and
java.lang.NoSuchMethodError: javax.xml.parsers.SAXParserFactory.setXIncludeAware