Saturday February 03, 2018
Apache CXF allows XML Schema validation of SOAP requests and responses to be activated from either the SOAP client or web service. While validation entails a performance penalty, it also helps validate restrictions not normally enforced by the JAXB databinding framework, such as length restrictions for strings or range restrictions on numeric data.
Activating validation from either the client or the web service side will handle both incoming and outgoing SOAP messages and return Java exceptions to the client should validation errors occur. At least for Tomcat, service-side validation will also result in the exceptions being recorded in the servlet container log.
To show a simple example of schema validation during SOAP calls, let's modify the DoubleIt WSDL to have partially overlapping restrictions on the types of numbers that can be doubled and acceptable ranges of responses that can be returned. This will allow us to see both SOAP request and response validation errors.
Modified DoubleIt's wsdl:types element with size restrictions:
<wsdl:definitions name="DoubleIt"
...
<wsdl:types>
<xsd:schema targetNamespace="http://www.example.org/schema/DoubleIt">
<xsd:element name="DoubleIt">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="numberToDouble">
<xsd:simpleType>
<xsd:restriction base="xsd:int">
<xsd:minInclusive value="10"/>
<xsd:maxInclusive value="20"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="DoubleItResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="doubledNumber">
<xsd:simpleType>
<xsd:restriction base="xsd:int">
<xsd:minInclusive value="24"/>
<xsd:maxInclusive value="36"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
...
</wsdl:definitions name="DoubleIt"
To activate Client-side validation: Use the modified WSClient class below. To activate validation, you can either use a programmatic API or add/modify the cxf.xml configuration file in the client's resources folder. Both options are shown below.
package client;
import javax.xml.ws.BindingProvider;
import org.example.contract.doubleit.DoubleItPortType;
import org.example.contract.doubleit.DoubleItService;
public class WSClient {
public WSClient() {
}
public static void main (String[] args) {
DoubleItService service = new DoubleItService();
DoubleItPortType port = service.getDoubleItPort();
System.out.println(doubleItMessage(port, 10));
System.out.println(doubleItMessage(port, 0));
System.out.println(doubleItMessage(port, -10));
}
public static String doubleItMessage(DoubleItPortType port, int numToDouble) {
// below line can be used instead of a cxf.xml file
((BindingProvider)port).getRequestContext().put("schema-validation-enabled", "true");
int resp = doubleIt(port, numToDouble);
return "The number " + numToDouble + " doubled is " + resp;
}
public static int doubleIt(DoubleItPortType port, int numToDouble) {
return port.doubleIt(numToDouble);
}
}
Second alternative: resources/cxf.xml in DoubleIt client (requires addition of Spring dependency to client's pom.xml):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:client name="{http://www.example.org/contract/DoubleIt}DoubleItPort"
createdFromAPI="true">
<jaxws:properties>
<entry key="schema-validation-enabled" value="true" />
</jaxws:properties>
</jaxws:client>
</beans>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.3.RELEASE</version>
</dependency>
After changing the WSDL and client code, be sure to rebuild the project via mvn clean install. A sample truncated CXF validation exception is shown below, CXF's actual command-line output is much more verbose as it automatically outputs stack traces for each exception to the terminal window. For client-side trapping of service-side activated validation exceptions, however, the stack traces will appear only in the service provider's log file.
WARNING: Interceptor for {http://www.example.org/contract/DoubleIt}DoubleItService#{http://www.example.org/contract/DoubleIt}DoubleIt has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Unmarshalling Error: cvc-minInclusive-valid: Value '20' is not facet-valid with respect to minInclusive '24' for type '#AnonType_doubledNumberDoubleItResponse'.
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:906)
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:712)
Caused by: javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 172; cvc-minInclusive-valid: Value '20' is not facet-valid with respect to minInclusive '24' for type '#AnonType_doubledNumberDoubleItResponse'.]
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:483)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:417)
To activate Service-side validation: For testing/tutorial purposes, probably best to shut off the client-side validation done above so it will not conflict with or override the validation being activated here. No change to the service bean is needed, just add the schema-validation-enabled property to the cxf-servlet.xml file:
<jaxws:endpoint
id="doubleit"
implementor="service.DoubleItPortTypeImpl"
wsdlLocation="WEB-INF/wsdl/DoubleIt.wsdl"
address="/doubleit">
<jaxws:properties>
<entry key="schema-validation-enabled" value="true"/>
</jaxws:properties>
</jaxws:endpoint>
After redeploying the web service provider, running the SOAP client will show both SOAP request and response exceptions logged into the Tomcat logs, as well as the appropriate exceptions returned to the SOAP client (again, even if the client is not explicitly activating schema validation on its side.) I have found the client-side exceptions returned to be somewhat cleaner when the validation is being activated service-side.
Additional Notes
wsdlLocation attribute in the cxf-servlet.xml file, so access to the full schemas are available when doing validation.Posted by Glen Mazza in Web Services at 07:00AM Feb 03, 2018 | Comments[0]