Spring Web Services 2
Spring Web Services 2
3.3 Data Contract
Now that we have seen some examples of the XML data that we will use,
it makes sense to formalize this into a schema. This
data contract
defines the message format we accept. There are four different ways
of defining such a contract for XML:
DTDs
XML Schema (XSD)
RELAX NG
Schematron
DTDs have limited namespace support, so they are not suitable for Web
services. Relax NG and Schematron certainly are easier
than XML Schema.
Unfortunately, they are not so widely supported across platforms. We
will use XML Schema.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://mycompany.com/hr/schemas"
xmlns:hr="http://mycompany.com/hr/schemas">
<xs:element name="HolidayRequest">
<xs:complexType>
<xs:sequence>
<xs:element ref="hr:Holiday"/>
<xs:element ref="hr:Employee"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Holiday">
<xs:complexType>
<xs:sequence>
<xs:element ref="hr:StartDate"/>
<xs:element ref="hr:EndDate"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Employee">
<xs:complexType>
<xs:sequence>
<xs:element ref="hr:Number"/>
<xs:element ref="hr:FirstName"/>
<xs:element ref="hr:LastName"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:hr="http://mycompany.com/hr/schemas"
elementFormDefault="qualified"
targetNamespace="http://mycompany.com/hr/schemas">
https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 10/71
09/03/2022 08:44 Spring Web Services Reference Documentation
<xs:element name="HolidayRequest">
<xs:complexType>
<xs:sequence>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="HolidayType">
<xs:sequence>
</xs:sequence>
</xs:complexType>
<xs:complexType name="EmployeeType">
<xs:sequence>
</xs:sequence>
</xs:complexType>
</xs:schema>
The schema still has one problem: with a schema like this, you
can expect the following messages to validate:
<HolidayRequest xmlns="http://mycompany.com/hr/schemas">
<Holiday>
<EndDate>neither is this</EndDate>
</Holiday>
</HolidayRequest>
Clearly, we must make sure that the start and end date are really dates.
XML Schema has an excellent built-in date type which
we can use. We also change the NCName s to
string s. Finally, we change the sequence in
<HolidayRequest/> to all .
This tells the XML parser that the order of
<Holiday/> and
<Employee/> is not significant. Our final
XSD now looks like this:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:hr="http://mycompany.com/hr/schemas"
elementFormDefault="qualified"
targetNamespace="http://mycompany.com/hr/schemas">
<xs:element name="HolidayRequest">
<xs:complexType>
<xs:all>
</xs:all>
</xs:complexType>
</xs:element>
<xs:complexType name="HolidayType">
<xs:sequence>
<xs:complexType name="EmployeeType">
<xs:sequence>
</xs:schema>
https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 11/71
09/03/2022 08:44 Spring Web Services Reference Documentation
We use the xsd:date data type, which consist of a year, month, and day, for
<StartDate/> and <EndDate/> .
xsd:string is used for the first and last name.
3.4 Service contract
A service contract is generally expressed as a WSDL file.
Note that in Spring-WS, writing the WSDL by hand is not required.
Based on the XSD and
some conventions, Spring-WS can create the WSDL for you, as explained in the section entitled
Section 3.6, “Implementing the Endpoint”.
You can skip to the next section if you want to; the
remainder of this section will show
you how to write your own WSDL by hand.
We start our WSDL with the standard preamble, and by importing our existing XSD. To
separate the schema from the definition,
we will use a separate namespace for the WSDL definitions:
http://mycompany.com/hr/definitions .
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:schema="http://mycompany.com/hr/schemas"
xmlns:tns="http://mycompany.com/hr/definitions"
targetNamespace="http://mycompany.com/hr/definitions">
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</xsd:schema>
</wsdl:types>
Next, we add our messages based on the written schema types. We only have one message: one with the
<HolidayRequest/> we put in the schema:
<wsdl:message name="HolidayRequest">
</wsdl:message>
<wsdl:portType name="HumanResource">
<wsdl:operation name="Holiday">
</wsdl:operation>
</wsdl:portType>
That finished the abstract part of the WSDL (the interface, as it were), and leaves the concrete part.
The concrete part consists of
a binding , which tells the client how
to invoke the operations you've just defined; and a service , which tells it
where to
invoke it.
Adding a concrete part is pretty standard: just refer to the abstract part you defined previously, make sure
you use
document/literal for the soap:binding elements
( rpc/encoded is deprecated), pick a soapAction for the operation
(in this
case http://mycompany.com/RequestHoliday , but any URI will do), and determine the
location URL where you want
request to come in (in this case
http://mycompany.com/humanresources ):
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:schema="http://mycompany.com/hr/schemas"
xmlns:tns="http://mycompany.com/hr/definitions"
targetNamespace="http://mycompany.com/hr/definitions">
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://mycompany.com/hr/schemas"
schemaLocation="hr.xsd"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="HolidayRequest">
https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 12/71
09/03/2022 08:44 Spring Web Services Reference Documentation
<wsdl:part element="schema:HolidayRequest" name="HolidayRequest"/>
</wsdl:message>
<wsdl:portType name="HumanResource">
<wsdl:operation name="Holiday">
</wsdl:portType>
<soap:operation soapAction="http://mycompany.com/RequestHoliday"/>
<wsdl:input name="HolidayRequest">
<soap:body use="literal"/>
</wsdl:input>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="HumanResourceService">
</wsdl:service>
</wsdl:definitions>
This is the final WSDL. We will describe how to implement the resulting schema and WSDL in the next section.
The following command creates a Maven3 web application project for us, using the Spring-WS archetype
(that is, project
template)
-DarchetypeArtifactId=spring-ws-archetype \
-DarchetypeVersion= \
-DgroupId=com.mycompany.hr \
-DartifactId=holidayService
This command will create a new directory called holidayService . In this directory,
there is a 'src/main/webapp' directory,
which will contain the root of the WAR file.
You will find the standard web application deployment descriptor
'WEB-INF/web.xml'
here, which defines a Spring-WS MessageDispatcherServlet and maps all incoming
requests to this
servlet.
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
In addition to the above 'WEB-INF/web.xml' file, you will also need another,
Spring-WS-specific configuration file, named
'WEB-INF/spring-ws-servlet.xml' .
This file contains all of the Spring-WS-specific beans such as EndPoints ,
WebServiceMessageReceivers , and suchlike, and is used to create a new Spring container.
The name of this file is derived
from the name of the attendant servlet (in this case
'spring-ws' ) with '-servlet.xml' appended to it.
So if you defined a
MessageDispatcherServlet with the name
'dynamite' , the name of the Spring-WS-specific configuration file would be
'WEB-INF/dynamite-servlet.xml' .
(You can see the contents of the 'WEB-INF/spring-ws-servlet.xml' file for this
example in ???.)
Once you had the project structure created, you can put the schema and wsdl from previous section into
'WEB-INF/' folder.
package com.mycompany.hr.ws;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import com.mycompany.hr.service.HumanResourceService;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.Namespace;
import org.jdom2.filter.Filters;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
@Endpoint
public class HolidayEndpoint {
https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 14/71
09/03/2022 08:44 Spring Web Services Reference Documentation
private XPathExpression<Element> startDateExpression;
@Autowired
this.humanResourceService = humanResourceService;
if (result != null) {
return dateFormat.parse(result.getText());
} else {
throw new IllegalArgumentException("Could not evaluate [" + expression + "] on [" + element + "]")
}
https://docs.spring.io/spring-ws/docs/2.4.0.RELEASE/reference/htmlsingle/ 15/71