Moved documentation from separate module into the main module, so that it is published with the site.

This commit is contained in:
Arjen Poutsma
2007-04-15 14:47:16 +00:00
parent 3c98f7988a
commit 2afad2ca80
19 changed files with 3677 additions and 12 deletions

View File

@@ -17,11 +17,6 @@
<name>JiBX Maven Repository</name>
<url>http://jibx.sourceforge.net/maven2/</url>
</repository>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven2</name>
<url>https://maven2-repository.dev.java.net/nonav/repository</url>
</repository>
</repositories>
<build>
<plugins>

72
pom.xml
View File

@@ -124,12 +124,6 @@
<module>samples</module>
</modules>
</profile>
<profile>
<id>doc</id>
<modules>
<module>doc</module>
</modules>
</profile>
</profiles>
<properties>
<spring.version>2.0.4</spring.version>
@@ -140,7 +134,19 @@
<name>Spring External Dependencies Repository</name>
<url>https://svn.sourceforge.net/svnroot/springframework/repos/repo-ext/</url>
</repository>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven2</name>
<url>https://maven-repository.dev.java.net/nonav/repository</url>
<layout>legacy</layout>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>agilejava</id>
<url>http://agilejava.com/maven/</url>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<!-- Building -->
@@ -181,6 +187,60 @@
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate-html</goal>
<goal>generate-pdf</goal>
</goals>
<phase>pre-site</phase>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.docbook</groupId>
<artifactId>docbook-xml</artifactId>
<version>4.4</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<configuration>
<includes>index.xml</includes>
<chunkedOutput>true</chunkedOutput>
<htmlStylesheet>css/html.css</htmlStylesheet>
<xincludeSupported>true</xincludeSupported>
<htmlCustomization>src/docbkx/resources/xsl/html_chunk.xsl</htmlCustomization>
<foCustomization>src/docbkx/resources/xsl/fopdf.xsl</foCustomization>
<entities>
<entity>
<name>version</name>
<value>${version}</value>
</entity>
</entities>
<postProcess>
<copy todir="target/site/reference">
<fileset dir="target/docbkx">
<include name="**/*.html"/>
<include name="**/*.pdf"/>
</fileset>
</copy>
<copy todir="target/site/reference/html">
<fileset dir="src/docbkx/resources">
<include name="**/*.css"/>
<include name="**/*.png"/>
<include name="**/*.gif"/>
<include name="**/*.jpg"/>
</fileset>
</copy>
<move file="target/site/reference/pdf/index.pdf"
tofile="target/site/reference/pdf/spring-ws-reference.pdf"
failonerror="false"/>
</postProcess>
</configuration>
</plugin>
</plugins>
</build>
<reporting>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>spring-ws</artifactId>
<groupId>org.springframework.ws</groupId>
<version>1.0-m4-SNAPSHOT</version>
<version>1.0-rc1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-ws-sandbox</artifactId>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE bibliography PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<bibliography>
<title>Bibliography</title>
<biblioentry id="waldo-94">
<authorgroup>
<author>
<firstname>Jim</firstname>
<surname>Waldo</surname>
</author>
<author>
<firstname>Ann</firstname>
<surname>Wollrath</surname>
</author>
<author>
<firstname>Sam</firstname>
<surname>Kendall</surname>
</author>
</authorgroup>
<title>A Note on Distributed Computing</title>
<publisher>
<publishername>Springer Verlag</publishername>
</publisher>
<date>1994</date>
</biblioentry>
<biblioentry id="alpine">
<authorgroup>
<author>
<firstname>Steve</firstname>
<surname>Loughran</surname>
</author>
<author>
<firstname>Edmund</firstname>
<surname>Smith</surname>
</author>
</authorgroup>
<title>Rethinking the Java SOAP Stack</title>
<date>May 17, 2005</date>
<copyright>
<year>2005</year>
<holder>IEEE Telephone Laboratories, Inc.</holder>
</copyright>
</biblioentry>
<biblioentry id="effective-enterprise-java">
<authorgroup>
<author>
<firstname>Ted</firstname>
<surname>Neward</surname>
</author>
</authorgroup>
<title>Effective Enterprise Java</title>
<publisher>
<publishername>Addison-Wesley</publishername>
</publisher>
<date>2004</date>
</biblioentry>
</bibliography>

160
src/docbkx/client.xml Normal file
View File

@@ -0,0 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="client">
<title>Using Spring Web Services on the Client</title>
<section>
<title>Introduction</title>
<para>
Spring-WS provides a client-side Web service API that allows for consistent, XML-driven access to Web
services. It also allows for use of <link linkend="oxm">marshallers and unmarshallers</link>.
</para>
<para>
The package <package>org.springframework.ws.client.core</package> provides the core functionality for using
the client-side access API. It contains template classes that simplifies the use of Web services, much like
the <classname>JdbcTemplate</classname> does for JDBC. The design principle common to Spring template
classes is to provide helper methods to perform common operations and for more sophisticated usage, delegate
the essence of the processing task to user implemented callback interfaces. The Web service template
follows the same design. The classes offer various
convenience methods for the sending and receiving of XML messages, marshalling objects to XML before sending,
and allows for multiple transports,
</para>
</section>
<section>
<title>Using the client-side API</title>
<section>
<title><classname>WebServiceTemplate</classname></title>
<para>
The <classname>WebServiceTemplate</classname> is the core class for client-side Web service access in
Spring-WS. It contains methods for sending <classname>Source</classname> objects, and receiving response
messages as either <classname>Source</classname> or <classname>Result</classname>. Additionally, it can
marshal objects to XML before sending them across a transport, and unmarshal the response XML into an
object again.
</para>
<section>
<title>Transports</title>
<para>
The <classname>WebServiceTemplate</classname> requires a reference to a
<classname>MessageSender</classname>. The message sender is responsible for sending the XML message
across a transport layer.
</para>
<para>
There are two implementations of the <classname>MessageSender</classname> interface for sending messages
via HTTP. The simplest implementation is the <classname>HttpUrlConnectionMessageSender</classname>,
which uses the facilities provided by Java SE itself. The alternative is the
<classname>CommonsHttpMessageSender</classname>, which uses the Jakarta Commons HttpClient. Use the
latter if you need more advanced and easy-to-use functionality. Both HTTP message senders require an
URL to be set using the <property>url</property> property.
</para>
</section>
<section>
<title>Message factories</title>
<para>
In addition to a message sender, the <classname>WebServiceTemplate</classname> requires a Web service
message factory. As explained in <xref linkend="message-factories"/>, there are two message factories
for SOAP: <classname>SaajSoapMessageFactory</classname> and
<classname>AxiomSoapMessageFactory</classname>.
</para>
</section>
</section>
<section>
<title>Sending and receiving a <interfacename>WebServiceMessage</interfacename></title>
<para>
The <classname>WebServiceTemplate</classname> contains many convenience methods to send and receive
web service messages. There are methods that take and return <interfacename>Source</interfacename>
and those that return a <interfacename>Result</interfacename>. Additionally, there are methods which
marshal and unmarshal objects to XML. Here is an example that sends a simple XML message to a Web
service.</para>
<programlisting><![CDATA[import java.io.IOException;
import java.io.StringReader;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.WebServiceMessageSender;
public class WebServiceClient {
private static final String MESSAGE = "<message xmlns=\"http://tempuri.org\">Hello World</message>";
private WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
public void setMessageFactory(WebServiceMessageFactory messageFactory) {
webServiceTemplate.setMessageFactory(messageFactory);
}
public void setMessageSender(WebServiceMessageSender messageSender) {
webServiceTemplate.setMessageSender(messageSender);
}
public void simpleSendAndReceive() throws IOException {
StreamSource source = new StreamSource(new StringReader(MESSAGE));
StreamResult result = new StreamResult(System.out);
webServiceTemplate.sendAndReceive(source, result);
}
}]]></programlisting>
<para>
Here is the corresponding configuration:
</para>
<programlisting><![CDATA[
<beans xmlns="http://www.springframework.org/schema/beans">
<bean id="webServiceClient" class="WebServiceClient">
<property name="messageFactory">
<bean class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
</property>
<property name="messageSender">
<bean class="org.springframework.ws.transport.http.HttpUrlConnectionMessageSender">
<property name="url" value="http://localhost:8080/WebService"/>
</bean>
</property>
</bean>
</beans>]]></programlisting>
<para>
This example uses the template to send a hello world message to the web service located at
<uri>http://localhost:8080/WebService</uri>, and writes the result to the console.
The <classname>WebServiceTemplate</classname> is injected with the message factory and sender.
A zero argument constructor and <property>messageFactory</property> /
<property>messageSender</property> bean properties are provided and can be used for constructing
the instance (using a BeanFactory or plain Java code). Alternatively, consider deriving from
Spring-WS's <classname>WebServiceGatewaySupport</classname> convenience base class, which provides
pre-built bean properties for configuration.
</para>
</section>
<section>
<title>Marshalling, sending, receiving, and unmarshalling</title>
<para>
In order to facilitate the sending of plain Java objects, the <classname>WebServiceTemplate</classname>
has a send methods that take an object as an argument for a message's data content.
The method <methodname>marshalSendAndReceive</methodname> in <classname>WebServiceTemplate</classname>
delegates the conversion of the request object to XML to a <interface>Marshaller</interface>, and
the conversion of the response XML to an object to an <interface>Unmarshaller</interface>.
For more information about marshalling and unmarshaller, refer to <xref linkend="oxm"/>.
By using the marshallers, you and your application code can focus on the business object that is being
sent or received and not be concerned with the details of how it is represented as XML.
In order to use the marshalling functionality, you have to set a marshaller and unmarshaller with the
<property>marshaller</property>/<property>unmarshaller</property> properties of the
<classname>WebServiceTemplate</classname>.
</para>
</section>
<section>
<title><interface>WebServiceMessageCallback</interface></title>
<para>
To accommodate the setting of a SOAP headers, and other settings on the message, the
<interfacename>WebServiceMessageCallback</interfacename> interface gives you access to the message
after it has been created, but before it is sent. The example below demonstrates how to set the SOAP
Action header on a message that is created by marshalling an object.
</para>
<programlisting><![CDATA[public void marshalWithSoapActionHeader(MyObject o) {
webServiceTemplate.marshalSendAndReceive(o, new WebServiceMessageCallback() {
public void doInMessage(WebServiceMessage message) {
((SoapMessage)message).setSoapAction("http://tempuri.org/Action");
}
});
}]]></programlisting>
</section>
</section>
</chapter>

46
src/docbkx/index.xml Normal file
View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<bookinfo>
<title>Spring Web Services - Reference Documentation</title>
<releaseinfo>
&version;
</releaseinfo>
<authorgroup>
<author>
<firstname>Arjen</firstname>
<surname>Poutsma</surname>
</author>
<author>
<firstname>Rick</firstname>
<surname>Evans</surname>
</author>
</authorgroup>
<legalnotice>
<para>
Copies of this document may be made for your own use and for distribution to others, provided that you
do not charge any fee for such copies and further provided that each copy contains this Copyright
Notice, whether distributed in print or electronically.
</para>
</legalnotice>
</bookinfo>
<toc />
<xi:include href="preface.xml" />
<xi:include href="overview.xml" />
<chapter id="server">
<title>Document-driven Web services with Spring-WS</title>
<para>This chapter will contain the reference for server-side Spring-WS usage.</para>
</chapter>
<!--<xi:include href="server.xml" />-->
<xi:include href="client.xml" />
<xi:include href="security.xml" />
<xi:include href="oxm.xml" />
<xi:include href="bibliography.xml" />
</book>

142
src/docbkx/overview.xml Normal file
View File

@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="introduction">
<title>Introduction</title>
<section>
<title>Overview</title>
<para>
Spring-WS consists of three separate modules. This chapter discusses each of the modules in turn.
</para>
<para>
The <link linkend="ws">Core</link> package is the central part of the Web services functionality. It
provides the central <classname>WebServiceMessage</classname> and <classname>SoapMessage</classname>
interfaces, the powerful message dispatching, and the various support classes for implementing Web service
endpoints.
</para>
<para>
The <link linkend="security">Security</link> package provides a WS-Security implementation that integrates
with the core Web service package. It allows you to add principal tokens, sign, and decrypt and encrypt SOAP
messages. Addtionally, it allows you to leverage your existing Acegi security implementation for
authentication and authorization.
</para>
<para>
The <link linkend="oxm">OXM</link> package provides integration for popular XML marshalling APIs, including
JAXB 1 and 2. Using the OXM package means that you benefit from a unified exception hierarchy, and can wire
up your favorite XML marshalling technology easily.
</para>
</section>
<section>
<title>Why Spring Web Services?</title>
<para>
There are various other SOAP stacks available, why and where should you use Spring-WS? This section answers
that question by showing what the focus of Spring-WS is.
</para>
<section>
<title>Spring-WS is meant for Public Web Services</title>
<para>
One can distinguish between two different sorts of Web services. Private Web services are not used
outside your application domain. They might form a part of your Enterprise Service Bus, or used as a
means to communicate between a fat .NET client and a J2EE server. When the two sides of the spectrum
(client and server) are under your control, you can easily expose (existing) methods, since you can
(re)generate client code easily.
</para>
<para>
Public Web services provide a separate interface to your application. They are often used by clients
that are outside of your reach. When developing a public Web service, you should really think about the
interface you are providing: it is probably going to be around for a while, and you cannot change it
that often. As such, it is a good idea to place the Web service in a separate layer, thus hiding the
inner workings of the application. As a result, you can change the Web service and the rest of the
appliciation seperately.
</para>
</section>
<section>
<title>Spring-WS makes Web Services First Class Citizens of the Architecture</title>
<para>
Web Services deserve a proper place in an application architecture. Often, they exist as an afterthought
in the application architecture, mostly because existing Java business interfaces are exposed as SOAP
services. One could say that they are "SOAPified". Spring-WS provides a MVC-like framework for
developing a Web service application layer, just like you would develop a layer especially for a Web
user interface using Spring-MVC. Spring-WS also provides useful integration points with you existing
Spring application architecture, such as the Acegi integration.
</para>
</section>
<section>
<title>Spring-WS is Data-Driven</title>
<para>
When Web Services started making their way into the Enterprise Computing world, developers considered
Web Services just another, XML-based remoting protocol. Such remoting frameworks can be used with
relative ease: on the server-side, one simply implements a specific interface such as
<classname>java.rmi.Remote</classname>, and on the client side, a dynamic proxy is used.
Unfortunately, because of this simplicity, remoting architectures have some issues:
<itemizedlist>
<listitem>
<para>
They pretend there is no <emphasis>latency</emphasis> between the client and the server,
while in fact there is both network and application latency,
</para>
</listitem>
<listitem>
<para>
They pretend that client and server have <emphasis>shared memory access</emphasis>, while in
fact data must be both marshalled and unmarshalled,
</para>
</listitem>
<listitem>
<para>
They ignore the possibility of a <emphasis>request or response not reaching its
destination</emphasis>,
</para>
</listitem>
<listitem>
<para>
They enforce a <emphasis>non-concurrent</emphasis> programming model, while in fact a
concurrent approach seems more in place,
</para>
</listitem>
<listitem>
<para>
They enforce a <emphasis>tightly coupled architecture</emphasis>, where changes on the
server-side result in changes on the client-side.
</para>
</listitem>
</itemizedlist>
It is not without reason that Gregor Hohpe calls a distributed architecture a <quote>fairy tale
architecture</quote>: one is made to believe things that simply are not true. To quote <xref
linkend="waldo-94"/>:
<blockquote>
<para>
Objects that interact in a distributed system need to be dealt with in ways that are
intrinsically different from objects that interact in a single address space.
</para>
</blockquote>
</para>
<para>
Instead of being behavior-driven, Spring-WS is data-driven: it focusses on the data being sent, not on a
particular method being invoked.
</para>
</section>
<section>
<title>Spring-WS Focusses on Contract-first Development</title>
<para>
SOAP services are defined in two contracts: the data contract (the XSD schema), and the service contract
(the WSDL). Generating these contracts from Java-code is called <emphasis>contract-last
development</emphasis> <xref linkend="alpine"/> identifies some problems with this approach, most
importantly:
<blockquote>
<para>
There is no way to ensure that a services published interface remains constant over time.
Every redeployment of the service may change the classes, and hence the contract.
</para>
</blockquote>
The alternative of contract-last development is <emphasis>contract-first development</emphasis>.
Using this approach, the service and data contract are leading. Spring-WS focusses on contract-first Web
service development, because is considered to be a best practice. After all, the actual XML that is sent
across the wire is more important than the Java code that is used to implement it.
</para>
</section>
</section>
</chapter>

709
src/docbkx/oxm.xml Normal file
View File

@@ -0,0 +1,709 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="oxm">
<title>Marshalling XML using O/X Mappers</title>
<section id="oxm-introduction">
<title>Introduction</title>
<para>
In this chapter, we will describe Spring's Object/XML Mapping support. Object/XML Mapping, or O/X mapping
for short, is the act of converting an XML document to and from an object. This conversion process is also
known as XML Marshalling, or XML Serialization. This chapter uses these terms interchangeably.
</para>
<para>
Within the field of O/X mapping, a
<emphasis>marshaller</emphasis>
is responsible for serializing an object (graph) to XML. In similar fashion, an
<emphasis>unmarshaller</emphasis>
deserializes the XML to an object graph. This XML can take the form of a DOM document, an input or output
stream, or a SAX handler.
</para>
<para>Some of the benefits of using Spring for your O/X mapping needs are:</para>
<formalpara>
<title>Ease of configuration</title>
<para>
Spring's bean factory makes it easy to configure marshallers, without needing to construct JAXB context,
JiBX binding factories, etc. The marshallers can be configured as any other bean in your application
context.
</para>
</formalpara>
<formalpara>
<title>Consistent Interfaces</title>
<para>
Spring's O/X mapping operates through two global interfaces: the
<classname>Marshaller</classname>
and
<classname>Unmarshaller</classname>
interface. These abstractions allow you to switch O/X mapping frameworks with relative ease, with little
or no changes required on the classes that do the marshalling. This approach has the additional benefit
of making it possible to do XML marshalling with a mix-and-match approach (e.g. some marshalling
performed using JAXB, other using XMLBeans) in a non-intrusive fashion, leveraging the strength of each
technology.
</para>
</formalpara>
<formalpara>
<title>Consistent Exception Hierarchy</title>
<para>
Spring provides a conversion from exceptions from the underlying O/X mapping tool to its own exception
hierarchy with the
<classname>XmlMappingException</classname>
as the root exception. As can be expected, these runtime exceptions wrap the original exception so no
information is lost.
</para>
</formalpara>
</section>
<section id="oxm-marshaller-unmarshaller">
<title>Marshaller and Unmarshaller</title>
<para>
As stated in the introduction, a
<emphasis>marshaller</emphasis>
serializes an object to XML, and an
<emphasis>unmarshaller</emphasis>
deserializes XML stream to an object. In this section, we will describe
the two Spring interfaces used for this purpose.
</para>
<section>
<title>Marshaller</title>
<para>
Spring abstracts all marshalling operations behind the
<classname>org.springframework.oxm.Marshaller</classname>
interface, which is listed below.
<programlisting><![CDATA[
public interface Marshaller {
/**
* Marshals the object graph with the given root into the provided Result.
*/
void marshal(Object graph, Result result)
throws XmlMappingException, IOException;
}]]></programlisting>
The
<classname>Marshaller</classname>
interface has just one method, which marshals the given
object to a given
<classname>javax.xml.transform.Result</classname>
. Result is a tagging interface that
basically represents an XML output abstraction: concrete implementations wrap various XML
representations, as indicated in the table below.
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>
<classname>javax.xml.transform.Result</classname>
implementation
</entry>
<entry>Wraps XML representation</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<classname>javax.xml.transform.dom.DOMResult</classname>
</entry>
<entry>
<classname>org.w3c.dom.Node</classname>
</entry>
</row>
<row>
<entry>
<classname>javax.xml.transform.sax.SAXResult</classname>
</entry>
<entry>
<classname>org.xml.sax.ContentHandler</classname>
</entry>
</row>
<row>
<entry>
<classname>javax.xml.transform.stream.StreamResult</classname>
</entry>
<entry>
<classname>java.io.File</classname>
,
<classname>java.io.OutputStream</classname>
,
or
<classname>java.io.Writer</classname>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<note>
<para>
Although the
<methodname>marshal</methodname>
method accepts a plain object as its first parameter,
most
<classname>Marshaller</classname>
implementations cannot handle arbitrary objects. Instead, an
object class must be mapped in a mapping file, registered with the marshaller, or have a common
base
class. Refer to the further sections in this chapter to determine how your O/X technology of
choice
manages this.
</para>
</note>
</para>
</section>
<section>
<title>Unmarshaller</title>
<para>
Similar to the
<classname>Marshaller</classname>
, there is the
<classname>org.springframework.oxm.Unmarshaller</classname>
interface.
<programlisting><![CDATA[
public interface Unmarshaller {
/**
* Unmarshals the given provided Source into an object graph.
*/
Object unmarshal(Source source)
throws XmlMappingException, IOException;
}]]></programlisting>
This interface also has one method, which reads from the given
<classname>javax.xml.transform.Source</classname>
(an XML input abstraction), and returns the
object read. As with Result, Source is a tagging interface that has three concrete implementations. Each
wraps a different XML representation, as indicated in the table below.
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>
<classname>javax.xml.transform.Source</classname>
implementation
</entry>
<entry>Wraps XML representation</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<classname>javax.xml.transform.dom.DOMSource</classname>
</entry>
<entry>
<classname>org.w3c.dom.Node</classname>
</entry>
</row>
<row>
<entry>
<classname>javax.xml.transform.sax.SAXSource</classname>
</entry>
<entry>
<classname>org.xml.sax.InputSource</classname>
and
<classname>org.xml.sax.XMLReader</classname>
</entry>
</row>
<row>
<entry>
<classname>javax.xml.transform.stream.StreamSource</classname>
</entry>
<entry>
<classname>java.io.File</classname>
,
<classname>java.io.InputStream</classname>
,
or
<classname>java.io.Reader</classname>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</section>
<para>
Even though there are two separate marshalling interfaces (
<classname>Marshaller</classname>
and
<classname>Unmarshaller</classname>
), most implementations found in Spring-WS implement both in one class.
This means that you can wire up one marshaller class and refer to it as marshaller and unmarshaller in your
<filename>applicationContext.xml</filename>
.
</para>
<section>
<title>XmlMappingException</title>
<para>
Spring converts exceptions from the underlying O/X mapping tool to its own exception hierarchy with the
<classname>XmlMappingException</classname>
as the root exception. As can be expected, these runtime
exceptions wrap the original exception so no information will be lost.
</para>
<para>
Additionally, the
<classname>MarshallingFailureException</classname>
and
<classname>UnmarshallingFailureException</classname>
provide a distinction between marshalling and
unmarshalling operations, even though the underlying O/X mapping tool does not do so.
</para>
<para>
The O/X Mapping exception hierarchy is shown in the following figure:
<mediaobject>
<imageobject role="fo">
<imagedata fileref="src/docbkx/resources/images/oxm-exceptions.svg"
format="SVG" align="center"/>
</imageobject>
<imageobject role="html">
<imagedata fileref="images/oxm-exceptions.png"
format="PNG" align="center"/>
</imageobject>
<caption>
<para>
O/X Mapping exception hierarchy
</para>
</caption>
</mediaobject>
</para>
</section>
</section>
<section id="oxm-usage">
<title>Using Marshaller and Unmarshaller</title>
<para>
Spring's OXM can be used for a wide variety of situations. In the following example, we will use it to
marshal the settings of a Spring-managed application as an XML file. We will use a simple JavaBean to
represent the settings:
<programlisting><![CDATA[
public class Settings {
private boolean fooEnabled;
public boolean isFooEnabled() {
return fooEnabled;
}
public void setFooEnabled(boolean fooEnabled) {
this.fooEnabled = fooEnabled;
}
}]]></programlisting>
</para>
<para>
The application class uses this bean to store its settings. Besides a main method, the class has two
methods:
<methodname>saveSettings</methodname>
saves the settings bean to a file named
<filename>settings.xml</filename>
, and
<methodname>loadSettings</methodname>
loads these settings again. A
<methodname>main</methodname>
method constructs a Spring application context, and calls these two methods.
<programlisting><![CDATA[
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
public class Application {
private static final String FILE_NAME = "settings.xml";
private Settings settings = new Settings();
private Marshaller marshaller;
private Unmarshaller unmarshaller;
public void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
public void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
public void saveSettings() throws IOException {
FileOutputStream os = null;
try {
os = new FileOutputStream(FILE_NAME);
this.marshaller.marshal(settings, new StreamResult(os));
} finally {
if (os != null) {
os.close();
}
}
}
public void loadSettings() throws IOException {
FileInputStream is = null;
try {
is = new FileInputStream(FILE_NAME);
this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
} finally {
if (is != null) {
is.close();
}
}
}
public static void main(String[] args) throws IOException {
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Application application = (Application) appContext.getBean("application");
application.saveSettings();
application.loadSettings();
}
}]]></programlisting>
The
<classname>Application</classname>
requires both a
<methodname>marshaller</methodname>
and
<methodname>unmarshaller</methodname>
property to be set. We can do so using the following
<filename>applicationContext.xml</filename>
:
<programlisting><![CDATA[
<beans>
<bean id="application" class="Application">
<property name="marshaller" ref="castorMarshaller" />
<property name="unmarshaller" ref="castorMarshaller" />
</bean>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
</beans>
]]></programlisting>
This application context uses Castor, but we could have used any of the other marshaller instances described
later in this chapter. Note that Castor does not require any further configuration by default, so the bean
definition is rather simple. Also note that the
<classname>CastorMarshaller</classname>
implements both
<classname>Marshaller</classname>
and
<classname>Unmarshaller</classname>
, so we can refer to the
<varname>castorMarshaller</varname>
bean in both the
<varname>marshaller</varname>
and
<varname>unmarshaller</varname>
property of the application.
</para>
<para>
This sample application produces the following
<filename>settings.xml</filename>
file:
<programlisting><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>
]]></programlisting>
</para>
</section>
<section id="oxm-jaxb">
<title>JAXB</title>
<para>
The JAXB binding compiler translates a W3C XML Schema into one or more Java classes, a
<filename>jaxb.properties</filename>
file, and possibly other files, depending on the specific implementation of JAXB. Alternatively, JAXB2
offers a way to generate a schema from annotated Java classes.
</para>
<para>
Spring supports both the JAXB 1.0 as the JAXB 2.0 API as XML marshalling strategy, following the
<classname>Marshaller</classname>
and
<classname>Unmarshaller</classname>
interfaces described in
<xref linkend="oxm-marshaller-unmarshaller"/>
. The corresponding integration classes reside in the
<classname>org.springframework.oxm.jaxb</classname>
package.
</para>
<section>
<title>Jaxb1Marshaller</title>
<para>
The
<classname>Jaxb1Marshaller</classname>
class implements both the Spring
<classname>Marshaller</classname>
and
<classname>Unmarshaller</classname>
interface. It requires a
context path to operate, which you can set using the
<varname>contextPath</varname>
property. The
context path is a list of colon (:) separated Java package names that contain schema derived classes.
The marshaller has an additional
<varname>validating</varname>
property which defines whether to
validate invoming XML.
</para>
<para>
The next sample bean configuration shows how to configure a
<classname>JaxbMarshaller</classname>
using the classes generated to
<varname>org.springframework.ws.samples.airline.schema</varname>
.
</para>
<programlisting><![CDATA[<beans>
<bean id="jaxb1Marshaller" class="org.springframework.oxm.jaxb.Jaxb1Marshaller">
<property name="contextPath" value="org.springframework.ws.samples.airline.schema"/>
</bean>
...
</beans>]]></programlisting>
</section>
<section>
<title>Jaxb2Marshaller</title>
<para>
The
<classname>Jaxb2Marshaller</classname>
can be configured using the same
<varname>contextPath</varname>
property as the
<classname>Jaxb1Marshaller</classname>
. However, it also offers a
<varname>classesToBeBound</varname>
property, which allows you to set an array of classes to be supported by the marshaller. Schema
validation is performed by specifying one or more schema resource to the bean, like so:
</para>
<programlisting><![CDATA[<beans>
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>org.springframework.oxm.jaxb.Flight</value>
<value>org.springframework.oxm.jaxb.Flights</value>
</list>
</property>
<property name="schema" value="classpath:org/springframework/oxm/schema.xsd"/>
</bean>
...
</beans>]]></programlisting>
</section>
</section>
<section id="oxm-castor">
<title>Castor</title>
<para>
Castor XML mapping is an open source XML binding framework. It allows you to transform the data contained in
a java object model into/from an XML document. By default, it does not require any further configuration,
though a mapping file can be used to have more control over the behavior of Castor.
</para>
<para>
For more information on Castor, refer to the
<ulink url="http://castor.org/xml-framework.html">
<citetitle>Castor web site</citetitle>
</ulink>
. The Spring integration classes reside in the
<classname>org.springframework.oxm.castor</classname>
package.
</para>
<section>
<title>CastorMarshaller</title>
<para>
As with JAXB, the
<classname>CastorMarshaller</classname>
implements both the
<classname>Marshaller</classname>
and
<classname>Unmarshaller</classname>
interface. It can be wired up
as follows:
</para>
<programlisting><![CDATA[
<beans>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
...
</beans>]]></programlisting>
</section>
<section>
<title>Mapping</title>
<para>
Although it is possible to rely on Castor's default marshalling behavior, it might be necessary to have
more control over it. This can be accomplished using a Castor mapping file. For more information, refer
to
<ulink url="http://castor.org/xml-mapping.html">Castor XML Mapping</ulink>
.
</para>
<para>
The mapping can be set using the
<methodname>mappingLocation</methodname>
resource property, indicated
below with a classpath resource.
</para>
<programlisting><![CDATA[
<beans>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" >
<property name="mappingLocation" value="classpath:mapping.xml" />
</bean>
</beans>
]]></programlisting>
</section>
</section>
<section id="oxm-xmlbeans">
<title>XMLBeans</title>
<para>
XMLBeans is an XML binding tool that has full XML Schema support, and offers full XML Infoset fidelity. It
takes a different approach that most other O/X mapping frameworks, in that all classes that are
generated from an XML Schema are all derived from
<classname>XmlObject</classname>
, and contain XML binding
information in them.
</para>
<para>
For more information on XMLBeans, refer to the
<ulink url="http://xmlbeans.apache.org/">
<citetitle>XMLBeans
web site
</citetitle>
</ulink>
. The Spring-WS integration classes reside in the
<classname>org.springframework.oxm.xmlbeans</classname>
package.
</para>
<section>
<title>XmlBeansMarshaller</title>
<para>
The
<classname>XmlBeansMarshaller</classname>
implements both the
<classname>Marshaller</classname>
and
<classname>Unmarshaller</classname>
interface. It can be wired up as follows:
</para>
<programlisting><![CDATA[
<beans>
<bean id="xmlBeansMarshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller" />
...
</beans>]]></programlisting>
<note>
<para>
Note that the
<classname>XmlBeansMarshaller</classname>
can only marshal objects of type
<classname>XmlObject</classname>
, and not every
<classname>java.lang.Object</classname>
.
</para>
</note>
</section>
</section>
<section id="oxm-jibx">
<title>JiBX</title>
<para>
The JiBX framework offers a solution similar to JDO does for ORM: a binding definition defines the
rules for how your Java objects are converted to or from XML. After preparing the binding and compiling the
classes, a JiBX binding compiler enhances the class files, and adds code to handle converting instances of
the classes from or to XML.
</para>
<para>
For more information on JiBX, refer to the
<ulink url="http://jibx.sourceforge.net/">
<citetitle>JiBX web
site
</citetitle>
</ulink>
. The Spring integration classes reside in the
<varname>org.springframework.oxm.jibx</varname>
package.
</para>
<section>
<title>JibxMarshaller</title>
<para>
The
<classname>JibxMarshaller</classname>
class implements both the
<classname>Marshaller</classname>
and
<classname>Unmarshaller</classname>
interface. To operate, it requires the name of the class to
marshall in, which you can set using the
<varname>targetClass</varname>
property. Optionally, you can
set the binding name using the
<varname>bindingName</varname>
property. In the next sample, we refer to
the
<classname>flightsBindingFactory</classname>
defined in the previous bean definition.
</para>
<programlisting><![CDATA[
<beans>
<bean id="jibxFlightsMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
<property name="targetClass">org.springframework.oxm.jibx.Flights</property>
</bean>
...
]]></programlisting>
<note>
<para>
A
<classname>JibxMarshaller</classname>
is configured for a single class. If you want to marshal
multiple classes, you have to configure multiple
<classname>JibxMarshaller</classname>
s with
different
<varname>targetClass</varname>
es.
</para>
</note>
</section>
</section>
<section id="oxm-xstream">
<title>XStream</title>
<para>
XStream is a simple library to serialize objects to XML and back again. It does not require any mapping, and
generates clean XML.
</para>
<para>
For more information on XStream, refer to the
<ulink url="http://xstream.codehaus.org/">
<citetitle>XStream
web site
</citetitle>
</ulink>
. The Spring integration classes reside in the
<varname>org.springframework.oxm.xstream</varname>
package.
</para>
<section>
<title>XStreamMarshaller</title>
<para>
The
<classname>XStreamMarshaller</classname>
does not require any configuration, and can be configured
in an application context directly. To further customize the XML, you can set an
<emphasis>alias map</emphasis>
, which consists of string aliases mapped to classes:
</para>
<programlisting><![CDATA[
<beans>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<props>
<prop key="Flight">org.springframework.oxm.xstream.Flight</prop>
</props>
</property>
</bean>
...
</beans>]]></programlisting>
<note>
<para>
Note that XStream is an XML serialization library, not a data binding library. Therefore, it has
limited namespace support. As such, it is rather unsuitable for usage within Web services.
</para>
</note>
</section>
</section>
</chapter>

22
src/docbkx/preface.xml Normal file
View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<preface id="preface">
<title>Preface</title>
<para>
Web services development is a complicated affair. There is SOAP, there is REST. There is SOAP 1.1, and there is
SOAP 1.2. There is rpc/encoded, and there is document/literal. There is WS-Addressing, WS-Security, WS-Policy,
and various other Web service specifications. Implementing Web services using abstractions that magically turn
Java into XML, but turn out to be leaky abstractions makes it even harder. Spring Web Services provides a
solution for building interoperable Web services, while making it clear what XML is received and sent across the
wire. Spring-WS provides a powerful <link linkend="ws">message dispatching framework</link>, various <link
linkend="oxm">XML marshalling</link> techniques that can be used outside a Web service environment, and a <link
linkend="security">WS-Security</link> solution that integrates with your existing application security
solution.
</para>
<para>
This document provides a reference guide to Spring-WS's features. Since this document is still a
work-in-progress, if you have any requests or comments, please post them on the support forums at <ulink
url="http://forum.springframework.org/forumdisplay.php?f=39"/>.
</para>
</preface>

View File

@@ -0,0 +1,421 @@
body {
text-align: justify;
margin-right: 2em;
margin-left: 2em;
}
a,
a[accesskey^
=
"h"
]
,
a[accesskey^
=
"n"
]
,
a[accesskey^
=
"u"
]
,
a[accesskey^
=
"p"
]
{
font-family: Verdana, Arial, helvetica, sans-serif
;
font-size:
12
px
;
color: #003399
;
}
a:active {
color: #003399;
}
a:visited {
color: #888888;
}
p {
font-family: Verdana, Arial, sans-serif;
}
dt {
font-family: Verdana, Arial, sans-serif;
font-size: 12px;
}
p, dl, dt, dd, blockquote {
color: #000000;
margin-bottom: 3px;
margin-top: 3px;
padding-top: 0px;
}
ol, ul, p {
margin-top: 6px;
margin-bottom: 6px;
}
p, blockquote {
font-size: 90%;
}
p.releaseinfo {
font-size: 100%;
font-weight: bold;
font-family: Verdana, Arial, helvetica, sans-serif;
padding-top: 10px;
}
p.pubdate {
font-size: 120%;
font-weight: bold;
font-family: Verdana, Arial, helvetica, sans-serif;
}
td {
font-size: 80%;
}
td, th, span {
color: #000000;
}
td[width^
=
"40%"
]
{
font-family: Verdana, Arial, helvetica, sans-serif
;
font-size:
12
px
;
color: #003399
;
}
table[summary^
=
"Navigation header"
]
tbody tr th[colspan^
=
"3"
]
{
font-family: Verdana, Arial, helvetica, sans-serif
;
}
blockquote {
margin-right: 0px;
}
h1, h2, h3, h4, h6, H6 {
color: #000000;
font-weight: 500;
margin-top: 0px;
padding-top: 14px;
font-family: Verdana, Arial, helvetica, sans-serif;
margin-bottom: 0px;
}
h2.title {
font-weight: 800;
margin-bottom: 8px;
}
h2.subtitle {
font-weight: 800;
margin-bottom: 20px;
}
.firstname, .surname {
font-size: 12px;
font-family: Verdana, Arial, helvetica, sans-serif;
}
table {
border-collapse: collapse;
border-spacing: 0;
border: 1px black;
empty-cells: hide;
margin: 10px 0px 30px 50px;
width: 90%;
}
div.table {
margin: 30px 0px 30px 0px;
border: 1px dashed gray;
padding: 10px;
}
div .table-contents table {
border: 1px solid black;
}
div.table > p.title {
padding-left: 10px;
}
table[summary^
=
"Navigation footer"
]
{
border-collapse: collapse
;
border-spacing:
0
;
border:
1
px black
;
empty-cells: hide
;
margin:
0
px
;
width:
100
%
;
}
table[summary^
=
"Note"
]
,
table[summary^
=
"Warning"
]
,
table[summary^
=
"Tip"
]
{
border-collapse: collapse
;
border-spacing:
0
;
border:
1
px black
;
empty-cells: hide
;
margin:
10
px
0
px
10
px
-
20
px
;
width:
100
%
;
}
td {
padding: 4pt;
font-family: Verdana, Arial, helvetica, sans-serif;
}
div.warning TD {
text-align: justify;
}
h1 {
font-size: 150%;
}
h2 {
font-size: 110%;
}
h3 {
font-size: 100%;
font-weight: bold;
}
h4 {
font-size: 90%;
font-weight: bold;
}
h5 {
font-size: 90%;
font-style: italic;
}
h6 {
font-size: 100%;
font-style: italic;
}
tt {
font-size: 110%;
font-family: "Courier New", Courier, monospace;
color: #000000;
}
.navheader, .navfooter {
border: none;
}
div.navfooter table {
border: dashed gray;
border-width: 1px 1px 1px 1px;
background-color: #cde48d;
}
pre {
font-size: 110%;
padding: 5px;
border-style: solid;
border-width: 1px;
border-color: #CCCCCC;
background-color: #f3f5e9;
}
ul, ol, li {
list-style: disc;
}
hr {
width: 100%;
height: 1px;
background-color: #CCCCCC;
border-width: 0px;
padding: 0px;
}
.variablelist {
padding-top: 10px;
padding-bottom: 10px;
margin: 0;
}
.term {
font-weight: bold;
}
.mediaobject {
padding-top: 30px;
padding-bottom: 30px;
}
.legalnotice {
font-family: Verdana, Arial, helvetica, sans-serif;
font-size: 12px;
font-style: italic;
}
.sidebar {
float: right;
margin: 10px 0px 10px 30px;
padding: 10px 20px 20px 20px;
width: 33%;
border: 1px solid black;
background-color: #F4F4F4;
font-size: 14px;
}
.property {
font-family: "Courier New", Courier, monospace;
}
a code {
font-family: Verdana, Arial, monospace;
font-size: 12px;
}
td code {
font-size: 110%;
}
div.note * td,
div.tip * td,
div.warning * td,
div.calloutlist * td {
text-align: justify;
font-size: 100%;
}
.programlisting .interfacename,
.programlisting .literal,
.programlisting .classname {
font-size: 95%;
}
.title .interfacename,
.title .literal,
.title .classname {
font-size: 130%;
}
/* everything in a <lineannotation/> is displayed in a coloured, comment-like font */
.programlisting * .lineannotation,
.programlisting * .lineannotation * {
color: green;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!-- Generated by dot version 1.13 (v16) (Mon August 23, 2004)
For user: (arjen) Arjen Poutsma Title: G Pages: 1 -->
<svg width="525pt" height="192pt"
viewBox = "-1 -1 524 191"
xmlns="http://www.w3.org/2000/svg">
<g id="graph0" class="graph" style="font-family:Times-Roman;font-size:14.00;">
<title>G</title>
<g id="node1" class="node"><title>c1</title>
<polygon style="fill:none;stroke:black;" points="259,40 374,40 374,4 259,4 259,40"/>
<text text-anchor="middle" x="316" y="25" style="font-family:Arial Italic;font-size:10.00;">XmlMappingException</text>
</g>
<g id="node2" class="node"><title>c2</title>
<polygon style="fill:none;stroke:black;" points="88,112 321,112 321,76 88,76 88,112"/>
<text text-anchor="middle" x="204" y="97" style="font-family:Arial Regular;font-size:10.00;">GenericMarshallingFailureException</text>
</g>
<g id="edge2" class="edge"><title>c1-&gt;c2</title>
<path style="fill:none;stroke:black;" d="M279,46C264,56 246,67 232,76"/>
<polygon style="fill:none;stroke:black;" points="278,43 288,40 282,48 278,43"/>
</g>
<g id="node8" class="node"><title>c5</title>
<polygon style="fill:none;stroke:black;" points="338,112 518,112 518,76 338,76 338,112"/>
<text text-anchor="middle" x="428" y="97" style="font-family:Arial Regular;font-size:10.00;">ValidationFailureException</text>
</g>
<g id="edge8" class="edge"><title>c1-&gt;c5</title>
<path style="fill:none;stroke:black;" d="M353,46C368,56 386,67 400,76"/>
<polygon style="fill:none;stroke:black;" points="350,48 344,40 354,43 350,48"/>
</g>
<g id="node4" class="node"><title>c3</title>
<polygon style="fill:none;stroke:black;" points="5,184 191,184 191,148 5,148 5,184"/>
<text text-anchor="middle" x="98" y="169" style="font-family:Arial Regular;font-size:10.00;">MarshallingFailureException</text>
</g>
<g id="edge4" class="edge"><title>c2-&gt;c3</title>
<path style="fill:none;stroke:black;" d="M168,118C154,128 138,139 124,148"/>
<polygon style="fill:none;stroke:black;" points="167,115 177,112 171,120 167,115"/>
</g>
<g id="node6" class="node"><title>c4</title>
<polygon style="fill:none;stroke:black;" points="209,184 413,184 413,148 209,148 209,184"/>
<text text-anchor="middle" x="311" y="169" style="font-family:Arial Regular;font-size:10.00;">UnmarshallingFailureException</text>
</g>
<g id="edge6" class="edge"><title>c2-&gt;c4</title>
<path style="fill:none;stroke:black;" d="M240,118C254,128 271,139 284,148"/>
<polygon style="fill:none;stroke:black;" points="237,120 231,112 241,115 237,120"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -0,0 +1,470 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This is the XSL FO (PDF) stylesheet for the Spring reference
documentation.
Thanks are due to Christian Bauer of the Hibernate project
team for writing the original stylesheet upon which this one
is based.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<xsl:import href="urn:docbkx:stylesheet"/>
<!--###################################################
Custom Title Page
################################################### -->
<xsl:template name="book.titlepage.recto">
<fo:block>
<fo:table table-layout="fixed" width="175mm">
<fo:table-column column-width="175mm"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell text-align="center">
<fo:block>
<fo:block font-family="Helvetica" font-size="24pt" padding-before="10mm">
<xsl:value-of select="bookinfo/title"/>
</fo:block>
</fo:block>
<fo:block font-family="Helvetica" font-size="22pt" padding-before="10mm">
<xsl:value-of select="bookinfo/subtitle"/>
</fo:block>
<fo:block font-family="Helvetica" font-size="12pt" padding="10mm">
<xsl:value-of select="bookinfo/releaseinfo"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell text-align="center">
<fo:block font-family="Helvetica" font-size="14pt" padding="10mm">
<xsl:value-of select="bookinfo/pubdate"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell text-align="center">
<fo:block font-family="Helvetica" font-size="12pt" padding="10mm">
<xsl:text>Copyright &#xA9; 2004-2007 </xsl:text>
<xsl:for-each select="bookinfo/authorgroup/author">
<xsl:if test="position() > 1">
<xsl:text>, </xsl:text>
</xsl:if>
<xsl:value-of select="firstname"/>
<xsl:text> </xsl:text>
<xsl:value-of select="surname"/>
</xsl:for-each>
</fo:block>
<fo:block font-family="Helvetica" font-size="10pt" padding="1mm">
<xsl:value-of select="bookinfo/legalnotice"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<!-- Prevent blank pages in output -->
<xsl:template name="book.titlepage.before.verso">
</xsl:template>
<xsl:template name="book.titlepage.verso">
</xsl:template>
<xsl:template name="book.titlepage.separator">
</xsl:template>
<!--###################################################
Header
################################################### -->
<!-- More space in the center header for long text -->
<xsl:attribute-set name="header.content.properties">
<xsl:attribute name="font-family">
<xsl:value-of select="$body.font.family"/>
</xsl:attribute>
<xsl:attribute name="margin-left">-5em</xsl:attribute>
<xsl:attribute name="margin-right">-5em</xsl:attribute>
</xsl:attribute-set>
<!--###################################################
Custom Footer
################################################### -->
<xsl:template name="footer.content">
<xsl:param name="pageclass" select="''"/>
<xsl:param name="sequence" select="''"/>
<xsl:param name="position" select="''"/>
<xsl:param name="gentext-key" select="''"/>
<xsl:variable name="Version">
<xsl:if test="//releaseinfo">
<xsl:text>Spring Web Services (</xsl:text>
<xsl:value-of select="//releaseinfo"/>
<xsl:text>)</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:choose>
<xsl:when test="$sequence='blank'">
<xsl:if test="$position = 'center'">
<xsl:value-of select="$Version"/>
</xsl:if>
</xsl:when>
<!-- for double sided printing, print page numbers on alternating sides (of the page) -->
<xsl:when test="$double.sided != 0">
<xsl:choose>
<xsl:when test="$sequence = 'even' and $position='left'">
<fo:page-number/>
</xsl:when>
<xsl:when test="$sequence = 'odd' and $position='right'">
<fo:page-number/>
</xsl:when>
<xsl:when test="$position='center'">
<xsl:value-of select="$Version"/>
</xsl:when>
</xsl:choose>
</xsl:when>
<!-- for single sided printing, print all page numbers on the right (of the page) -->
<xsl:when test="$double.sided = 0">
<xsl:choose>
<xsl:when test="$position='center'">
<xsl:value-of select="$Version"/>
</xsl:when>
<xsl:when test="$position='right'">
<fo:page-number/>
</xsl:when>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:template>
<!--###################################################
Custom Toc Line
################################################### -->
<!-- The default DocBook XSL TOC printing is seriously broken... -->
<xsl:template name="toc.line">
<xsl:variable name="id">
<xsl:call-template name="object.id"/>
</xsl:variable>
<xsl:variable name="label">
<xsl:apply-templates select="." mode="label.markup"/>
</xsl:variable>
<!-- justify-end removed from block attributes (space problem in title.markup) -->
<fo:block end-indent="{$toc.indent.width}pt"
last-line-end-indent="-{$toc.indent.width}pt"
white-space-treatment="preserve"
text-align="left"
white-space-collapse="false">
<fo:inline keep-with-next.within-line="always">
<!-- print Chapters in bold style -->
<xsl:choose>
<xsl:when test="local-name(.) = 'chapter'">
<xsl:attribute name="font-weight">bold</xsl:attribute>
</xsl:when>
</xsl:choose>
<fo:basic-link internal-destination="{$id}">
<xsl:if test="$label != ''">
<xsl:copy-of select="$label"/>
<fo:inline white-space-treatment="preserve"
white-space-collapse="false">
<xsl:value-of select="$autotoc.label.separator"/>
</fo:inline>
</xsl:if>
<xsl:apply-templates select="." mode="title.markup"/>
</fo:basic-link>
</fo:inline>
<fo:inline keep-together.within-line="always">
<xsl:text> </xsl:text>
<fo:leader leader-pattern="dots"
leader-pattern-width="3pt"
leader-alignment="reference-area"
keep-with-next.within-line="always"/>
<xsl:text> </xsl:text>
<fo:basic-link internal-destination="{$id}">
<fo:page-number-citation ref-id="{$id}"/>
</fo:basic-link>
</fo:inline>
</fo:block>
</xsl:template>
<!--###################################################
Extensions
################################################### -->
<!-- These extensions are required for table printing and other stuff -->
<xsl:param name="use.extensions">1</xsl:param>
<xsl:param name="tablecolumns.extension">0</xsl:param>
<xsl:param name="callout.extensions">1</xsl:param>
<!-- FOP provide only PDF Bookmarks at the moment -->
<xsl:param name="fop.extensions">1</xsl:param>
<!--###################################################
Table Of Contents
################################################### -->
<!-- Generate the TOCs for named components only -->
<xsl:param name="generate.toc">
book toc
</xsl:param>
<!-- Show only Sections up to level 3 in the TOCs -->
<xsl:param name="toc.section.depth">2</xsl:param>
<!-- Dot and Whitespace as separator in TOC between Label and Title-->
<xsl:param name="autotoc.label.separator" select="'. '"/>
<!--###################################################
Paper & Page Size
################################################### -->
<!-- Paper type, no headers on blank pages, no double sided printing -->
<xsl:param name="paper.type" select="'A4'"/>
<xsl:param name="double.sided">0</xsl:param>
<xsl:param name="headers.on.blank.pages">0</xsl:param>
<xsl:param name="footers.on.blank.pages">0</xsl:param>
<!-- Space between paper border and content (chaotic stuff, don't touch) -->
<xsl:param name="page.margin.top">5mm</xsl:param>
<xsl:param name="region.before.extent">10mm</xsl:param>
<xsl:param name="body.margin.top">10mm</xsl:param>
<xsl:param name="body.margin.bottom">15mm</xsl:param>
<xsl:param name="region.after.extent">10mm</xsl:param>
<xsl:param name="page.margin.bottom">0mm</xsl:param>
<xsl:param name="page.margin.outer">18mm</xsl:param>
<xsl:param name="page.margin.inner">18mm</xsl:param>
<!-- No intendation of Titles -->
<xsl:param name="title.margin.left">0pc</xsl:param>
<!--###################################################
Fonts & Styles
################################################### -->
<!-- Left aligned text and no hyphenation -->
<xsl:param name="alignment">justify</xsl:param>
<xsl:param name="hyphenate">false</xsl:param>
<!-- Default Font size -->
<xsl:param name="body.font.master">11</xsl:param>
<xsl:param name="body.font.small">8</xsl:param>
<!-- Line height in body text -->
<xsl:param name="line-height">1.4</xsl:param>
<!-- Monospaced fonts are smaller than regular text -->
<xsl:attribute-set name="monospace.properties">
<xsl:attribute name="font-family">
<xsl:value-of select="$monospace.font.family"/>
</xsl:attribute>
<xsl:attribute name="font-size">0.8em</xsl:attribute>
</xsl:attribute-set>
<!--###################################################
Tables
################################################### -->
<!-- The table width should be adapted to the paper size -->
<xsl:param name="default.table.width">17.4cm</xsl:param>
<!-- Some padding inside tables -->
<xsl:attribute-set name="table.cell.padding">
<xsl:attribute name="padding-left">4pt</xsl:attribute>
<xsl:attribute name="padding-right">4pt</xsl:attribute>
<xsl:attribute name="padding-top">4pt</xsl:attribute>
<xsl:attribute name="padding-bottom">4pt</xsl:attribute>
</xsl:attribute-set>
<!-- Only hairlines as frame and cell borders in tables -->
<xsl:param name="table.frame.border.thickness">0.1pt</xsl:param>
<xsl:param name="table.cell.border.thickness">0.1pt</xsl:param>
<!--###################################################
Labels
################################################### -->
<!-- Label Chapters and Sections (numbering) -->
<xsl:param name="chapter.autolabel">1</xsl:param>
<xsl:param name="section.autolabel" select="1"/>
<xsl:param name="section.label.includes.component.label" select="1"/>
<!--###################################################
Titles
################################################### -->
<!-- Chapter title size -->
<xsl:attribute-set name="chapter.titlepage.recto.style">
<xsl:attribute name="text-align">left</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="font-size">
<xsl:value-of select="$body.font.master * 1.8"/>
<xsl:text>pt</xsl:text>
</xsl:attribute>
</xsl:attribute-set>
<!-- Why is the font-size for chapters hardcoded in the XSL FO templates?
Let's remove it, so this sucker can use our attribute-set only... -->
<xsl:template match="title" mode="chapter.titlepage.recto.auto.mode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
xsl:use-attribute-sets="chapter.titlepage.recto.style">
<xsl:call-template name="component.title">
<xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/>
</xsl:call-template>
</fo:block>
</xsl:template>
<!-- Sections 1, 2 and 3 titles have a small bump factor and padding -->
<xsl:attribute-set name="section.title.level1.properties">
<xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
<xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
<xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
<xsl:attribute name="font-size">
<xsl:value-of select="$body.font.master * 1.5"/>
<xsl:text>pt</xsl:text>
</xsl:attribute>
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="section.title.level2.properties">
<xsl:attribute name="space-before.optimum">0.6em</xsl:attribute>
<xsl:attribute name="space-before.minimum">0.6em</xsl:attribute>
<xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
<xsl:attribute name="font-size">
<xsl:value-of select="$body.font.master * 1.25"/>
<xsl:text>pt</xsl:text>
</xsl:attribute>
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="section.title.level3.properties">
<xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
<xsl:attribute name="space-before.minimum">0.4em</xsl:attribute>
<xsl:attribute name="space-before.maximum">0.4em</xsl:attribute>
<xsl:attribute name="font-size">
<xsl:value-of select="$body.font.master * 1.0"/>
<xsl:text>pt</xsl:text>
</xsl:attribute>
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
</xsl:attribute-set>
<!-- Titles of formal objects (tables, examples, ...) -->
<xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing">
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="font-size">
<xsl:value-of select="$body.font.master"/>
<xsl:text>pt</xsl:text>
</xsl:attribute>
<xsl:attribute name="hyphenate">false</xsl:attribute>
<xsl:attribute name="space-after.minimum">0.4em</xsl:attribute>
<xsl:attribute name="space-after.optimum">0.6em</xsl:attribute>
<xsl:attribute name="space-after.maximum">0.8em</xsl:attribute>
</xsl:attribute-set>
<!--###################################################
Programlistings
################################################### -->
<!-- Verbatim text formatting (programlistings) -->
<xsl:attribute-set name="monospace.verbatim.properties">
<xsl:attribute name="font-size">
<xsl:value-of select="$body.font.small * 1.0"/>
<xsl:text>pt</xsl:text>
</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="verbatim.properties">
<xsl:attribute name="space-before.minimum">1em</xsl:attribute>
<xsl:attribute name="space-before.optimum">1em</xsl:attribute>
<xsl:attribute name="space-before.maximum">1em</xsl:attribute>
<xsl:attribute name="border-color">#444444</xsl:attribute>
<xsl:attribute name="border-style">solid</xsl:attribute>
<xsl:attribute name="border-width">0.1pt</xsl:attribute>
<xsl:attribute name="padding-top">0.5em</xsl:attribute>
<xsl:attribute name="padding-left">0.5em</xsl:attribute>
<xsl:attribute name="padding-right">0.5em</xsl:attribute>
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
<xsl:attribute name="margin-left">0.5em</xsl:attribute>
<xsl:attribute name="margin-right">0.5em</xsl:attribute>
</xsl:attribute-set>
<!-- Shade (background) programlistings -->
<xsl:param name="shade.verbatim">1</xsl:param>
<xsl:attribute-set name="shade.verbatim.style">
<xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
</xsl:attribute-set>
<!--###################################################
Callouts
################################################### -->
<!-- Use images for callouts instead of (1) (2) (3) -->
<xsl:param name="callout.graphics">0</xsl:param>
<xsl:param name="callout.unicode">1</xsl:param>
<!-- Place callout marks at this column in annotated areas -->
<xsl:param name="callout.defaultcolumn">90</xsl:param>
<!--###################################################
Admonitions
################################################### -->
<!-- Use nice graphics for admonitions -->
<xsl:param name="admon.graphics">'1'</xsl:param>
<!-- <xsl:param name="admon.graphics.path">&admon_gfx_path;</xsl:param> -->
<!--###################################################
Misc
################################################### -->
<!-- Placement of titles -->
<xsl:param name="formal.title.placement">
figure after
example before
equation before
table before
procedure before
</xsl:param>
<!-- Format Variable Lists as Blocks (prevents horizontal overflow) -->
<xsl:param name="variablelist.as.blocks">1</xsl:param>
<!-- The horrible list spacing problems -->
<xsl:attribute-set name="list.block.spacing">
<xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
<xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
<xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
</xsl:attribute-set>
<!--###################################################
colored and hyphenated links
################################################### -->
<xsl:template match="ulink">
<fo:basic-link external-destination="{@url}"
xsl:use-attribute-sets="xref.properties"
text-decoration="underline"
color="blue">
<xsl:choose>
<xsl:when test="count(child::node())=0">
<xsl:value-of select="@url"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</fo:basic-link>
</xsl:template>
</xsl:stylesheet>

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This is the XSL HTML configuration file for the Spring
Reference Documentation.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<xsl:import href="urn:docbkx:stylesheet"/>
<!--###################################################
HTML Settings
################################################### -->
<xsl:param name="html.stylesheet">html.css</xsl:param>
<!-- These extensions are required for table printing and other stuff -->
<xsl:param name="use.extensions">1</xsl:param>
<xsl:param name="tablecolumns.extension">0</xsl:param>
<xsl:param name="callout.extensions">1</xsl:param>
<xsl:param name="graphicsize.extension">0</xsl:param>
<!--###################################################
Table Of Contents
################################################### -->
<!-- Generate the TOCs for named components only -->
<xsl:param name="generate.toc">
book toc
</xsl:param>
<!-- Show only Sections up to level 3 in the TOCs -->
<xsl:param name="toc.section.depth">3</xsl:param>
<!--###################################################
Labels
################################################### -->
<!-- Label Chapters and Sections (numbering) -->
<xsl:param name="chapter.autolabel">1</xsl:param>
<xsl:param name="section.autolabel" select="1"/>
<xsl:param name="section.label.includes.component.label" select="1"/>
<!--###################################################
Callouts
################################################### -->
<!-- Use images for callouts instead of (1) (2) (3) -->
<xsl:param name="callout.graphics">0</xsl:param>
<!-- Place callout marks at this column in annotated areas -->
<xsl:param name="callout.defaultcolumn">90</xsl:param>
<!--###################################################
Admonitions
################################################### -->
<!-- Use nice graphics for admonitions -->
<xsl:param name="admon.graphics">0</xsl:param>
<!--###################################################
Misc
################################################### -->
<!-- Placement of titles -->
<xsl:param name="formal.title.placement">
figure after
example before
equation before
table before
procedure before
</xsl:param>
<xsl:template match="author" mode="titlepage.mode">
<xsl:if test="name(preceding-sibling::*[1]) = 'author'">
<xsl:text>, </xsl:text>
</xsl:if>
<span class="{name(.)}">
<xsl:call-template name="person.name"/>
<xsl:apply-templates mode="titlepage.mode" select="./contrib"/>
<xsl:apply-templates mode="titlepage.mode" select="./affiliation"/>
</span>
</xsl:template>
<xsl:template match="authorgroup" mode="titlepage.mode">
<div class="{name(.)}">
<h2>Authors</h2>
<p/>
<xsl:apply-templates mode="titlepage.mode"/>
</div>
</xsl:template>
</xsl:stylesheet>

View File

@@ -0,0 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This is the XSL HTML configuration file for the Spring Reference Documentation.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<xsl:import href="urn:docbkx:stylesheet"/>
<!--###################################################
HTML Settings
################################################### -->
<xsl:param name="chunk.section.depth">'5'</xsl:param>
<xsl:param name="use.id.as.filename">'1'</xsl:param>
<xsl:param name="html.stylesheet">html.css</xsl:param>
<!-- These extensions are required for table printing and other stuff -->
<xsl:param name="use.extensions">1</xsl:param>
<xsl:param name="tablecolumns.extension">0</xsl:param>
<xsl:param name="callout.extensions">1</xsl:param>
<xsl:param name="graphicsize.extension">0</xsl:param>
<!--###################################################
Table Of Contents
################################################### -->
<!-- Generate the TOCs for named components only -->
<xsl:param name="generate.toc">
book toc
</xsl:param>
<!-- Show only Sections up to level 3 in the TOCs -->
<xsl:param name="toc.section.depth">3</xsl:param>
<!--###################################################
Labels
################################################### -->
<!-- Label Chapters and Sections (numbering) -->
<xsl:param name="chapter.autolabel">1</xsl:param>
<xsl:param name="section.autolabel" select="1"/>
<xsl:param name="section.label.includes.component.label" select="1"/>
<!--###################################################
Callouts
################################################### -->
<!-- Place callout marks at this column in annotated areas -->
<xsl:param name="callout.defaultcolumn">90</xsl:param>
<!--###################################################
Misc
################################################### -->
<!-- Placement of titles -->
<xsl:param name="formal.title.placement">
figure after
example before
equation before
table before
procedure before
</xsl:param>
<xsl:template match="author" mode="titlepage.mode">
<xsl:if test="name(preceding-sibling::*[1]) = 'author'">
<xsl:text>, </xsl:text>
</xsl:if>
<span class="{name(.)}">
<xsl:call-template name="person.name"/>
<xsl:apply-templates mode="titlepage.mode" select="./contrib"/>
<xsl:apply-templates mode="titlepage.mode" select="./affiliation"/>
</span>
</xsl:template>
<xsl:template match="authorgroup" mode="titlepage.mode">
<div class="{name(.)}">
<h2>Authors</h2>
<p/>
<xsl:apply-templates mode="titlepage.mode"/>
</div>
</xsl:template>
<!--###################################################
Headers and Footers
################################################### -->
<!-- let's have a Spring and I21 banner across the top of each page -->
<xsl:template name="user.header.navigation">
<div style="background-color:white;border:none;height:73px;border:1px solid black;">
<a style="border:none;" href="http://static.springframework.org/spring-ws/site/"
title="The Spring Framework - Spring Web Services">
<img style="border:none;" src="images/xdev-spring_logo.jpg"/>
</a>
<a style="border:none;" href="http://www.interface21.com/" title="Interface21 - Spring from the Source">
<img style="border:none;position:absolute;padding-top:5px;right:42px;" src="images/i21-banner-rhs.jpg"/>
</a>
</div>
</xsl:template>
<!-- no other header navigation (prev, next, etc.) -->
<xsl:template name="header.navigation"/>
<xsl:param name="navig.showtitles">1</xsl:param>
<!-- let's have a 'Sponsored by Interface21' strapline (or somesuch) across the bottom of each page -->
<xsl:template name="footer.navigation">
<xsl:param name="prev" select="/foo"/>
<xsl:param name="next" select="/foo"/>
<xsl:param name="nav.context"/>
<xsl:variable name="home" select="/*[1]"/>
<xsl:variable name="up" select="parent::*"/>
<xsl:variable name="row1" select="count($prev) &gt; 0
or count($up) &gt; 0
or count($next) &gt; 0"/>
<xsl:variable name="row2" select="($prev and $navig.showtitles != 0)
or (generate-id($home) != generate-id(.)
or $nav.context = 'toc')
or ($chunk.tocs.and.lots != 0
and $nav.context != 'toc')
or ($next and $navig.showtitles != 0)"/>
<xsl:if test="$suppress.navigation = '0' and $suppress.footer.navigation = '0'">
<div class="navfooter">
<xsl:if test="$footer.rule != 0">
<hr/>
</xsl:if>
<xsl:if test="$row1 or $row2">
<table width="100%" summary="Navigation footer">
<xsl:if test="$row1">
<tr>
<td width="40%" align="left">
<xsl:if test="count($prev)>0">
<a accesskey="p">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$prev"/>
</xsl:call-template>
</xsl:attribute>
<xsl:call-template name="navig.content">
<xsl:with-param name="direction" select="'prev'"/>
</xsl:call-template>
</a>
</xsl:if>
<xsl:text>&#160;</xsl:text>
</td>
<td width="20%" align="center">
<xsl:choose>
<xsl:when test="$home != . or $nav.context = 'toc'">
<a accesskey="h">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$home"/>
</xsl:call-template>
</xsl:attribute>
<xsl:call-template name="navig.content">
<xsl:with-param name="direction" select="'home'"/>
</xsl:call-template>
</a>
<xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'">
<xsl:text>&#160;|&#160;</xsl:text>
</xsl:if>
</xsl:when>
<xsl:otherwise>&#160;</xsl:otherwise>
</xsl:choose>
<xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'">
<a accesskey="t">
<xsl:attribute name="href">
<xsl:apply-templates select="/*[1]" mode="recursive-chunk-filename">
<xsl:with-param name="recursive" select="true()"/>
</xsl:apply-templates>
<xsl:text>-toc</xsl:text>
<xsl:value-of select="$html.ext"/>
</xsl:attribute>
<xsl:call-template name="gentext">
<xsl:with-param name="key" select="'nav-toc'"/>
</xsl:call-template>
</a>
</xsl:if>
</td>
<td width="40%" align="right">
<xsl:text>&#160;</xsl:text>
<xsl:if test="count($next)>0">
<a accesskey="n">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$next"/>
</xsl:call-template>
</xsl:attribute>
<xsl:call-template name="navig.content">
<xsl:with-param name="direction" select="'next'"/>
</xsl:call-template>
</a>
</xsl:if>
</td>
</tr>
</xsl:if>
<xsl:if test="$row2">
<tr>
<td width="40%" align="left" valign="top">
<xsl:if test="$navig.showtitles != 0">
<xsl:apply-templates select="$prev" mode="object.title.markup"/>
</xsl:if>
<xsl:text>&#160;</xsl:text>
</td>
<td width="20%" align="center">
<span style="color:white;font-size:90%;">
<a href="http://www.interface21.com/"
title="Interface21 - Spring from the Source">Sponsored by Interface21
</a>
</span>
</td>
<td width="40%" align="right" valign="top">
<xsl:text>&#160;</xsl:text>
<xsl:if test="$navig.showtitles != 0">
<xsl:apply-templates select="$next" mode="object.title.markup"/>
</xsl:if>
</td>
</tr>
</xsl:if>
</table>
</xsl:if>
</div>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

890
src/docbkx/security.xml Normal file
View File

@@ -0,0 +1,890 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="security">
<title>Securing your Web services with Spring-WS</title>
<section id="security-introduction">
<title>Introduction</title>
<para>
In this chapter, we will show you how to add WS-Security aspects to your Web services. We will focus on the
three different areas of WS-Security, namely:
</para>
<formalpara>
<title>Authentication</title>
<para>
This is the process of determining whether a
<emphasis>principal</emphasis>
is who they claim to be. In this context, a "principal" generally means a user, device or some other
system which can perform an action in your application.
</para>
</formalpara>
<formalpara>
<title>Digital signatures</title>
<para>
The digital signature of a message is a piece of information based on both the document and the signer's
private key. It is created through the use of a hash function and a private signing function (encrypting
with the signer's private key).
</para>
</formalpara>
<formalpara>
<title>Encryption and Decryption</title>
<para>
<emphasis>Encryption</emphasis>
is the process of transforming data into a form that is impossible to read without the appropriate key.
It is mainly used to keep information hidden from anyone for whom it is not intended.
<emphasis>Decryption</emphasis>
is the reverse of encryption; it is the process of transforming of encrypted data back into an readable
form.
</para>
</formalpara>
<para>
All of these three areas are implemented using the
<classname>XwsSecurityInterceptor</classname>
, which we will describe in
<xref linkend="security-xws-security-interceptor" />
</para>
<note>
<para>
Note that WS-Security (especially encryption and signing) requires substantial amounts of memory, and
will also decrease performance. If performance is important to you, you might want to consider using not
using WS-Security.
</para>
</note>
</section>
<section id="security-xws-security-interceptor">
<title>XwsSecurityInterceptor</title>
<para>
The
<classname>XwsSecurityInterceptor</classname>
is an
<classname>EndpointInterceptor</classname>
(see
<xref linkend="ws-endpoint-interceptor" />
) that is based on SUN's XML and Web Services Security package (XWSS). This WS-Security implementation is
part of the Java Web Services Developer Pack (
<ulink url="http://java.sun.com/webservices/">
<citetitle>Java WSDP</citetitle>
</ulink>
).
</para>
<para>
Like any other endpoint interceptor, it is defined in the endpoint mapping (see
<xref linkend="ws-endpoint-mapping" />
). This means that you can be selective about adding WS-Security support: some endpoint mappings require it,
while others do not.
</para>
<para>
The
<classname>XwsSecurityInterceptor</classname>
requires a
<emphasis>security policy file</emphasis>
to operate. This XML file tells the interceptor what security aspects to require from incoming SOAP
messages, and what aspects to add to outgoing messages. The basic format of the policy file will be
explained in the following sections, but you can find a more in-depth tutorial
<ulink url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp564887">
<citetitle>here</citetitle>
</ulink>
. You can set the policy with the
<methodname>policyConfiguration</methodname>
property, which requires a Spring resource. The policy file can contain multiple elements, e.g. require a
username token on incoming messages, and sign all outgoing messages. It contains a
<literal>SecurityConfiguration</literal>
element as root (not a
<literal>JAXRPCSecurity</literal>
element).
</para>
<para>
Additionally, the security interceptor requires one or more
<classname>CallbackHandler</classname>
s to operate. These handlers are used to retrieve certificates, private keys, validate user credentials,
etc. Spring-WS offers handlers for most common security concerns, e.g. authenticating against a Acegi
authentication manager, signing outgoing messages based on a X509 certificate. The following sections will
indicate what callback handler to use for which security concern. You can set the callback handlers using
the
<methodname>callbackHandler</methodname>
or
<methodname>callbackHandlers</methodname>
property.
</para>
<para>
Here is an example that shows how to wire the
<classname>XwsSecurityInterceptor</classname>
up:
<programlisting><![CDATA[
<beans>
<bean id="wsSecurityInterceptor"
class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
<property name="policyConfiguration" value="classpath:securityPolicy.xml"/>
<property name="callbackHandlers">
<list>
<ref bean="certificateHandler"/>
<ref bean="authenticationHandler"/>
</list>
</property>
</bean>
...
</beans>
]]></programlisting>
This interceptor is configured using the <filename>securityPolicy.xml</filename> file on the classpath. It
uses two callback handlers which are defined further on in the file.
</para>
</section>
<section id="keystore">
<title>Key stores</title>
<para>
For most cryptographic operations, you will use standard <classname>java.security.KeyStore</classname>
objects. This includes certificate verification, message signing, signature verification, encryption, but
excludes username and time-stamp verification. This section aims to give you some background knowledge on
key stores, and the Java tools that you can use to store keys and certificates in a key store file. This
information is mostly not related to Spring-WS, but to the general cryptographic features of Java.
</para>
<para>
The <classname>java.security.KeyStore</classname> class represents a storage facility for cryptographic keys
and certificates. It can contain three different sort of elements:
</para>
<formalpara>
<title>Private Keys</title>
<para>
These keys are used for self-authentication. The private key is accompanied by certificate chain for
the corresponding public key. Within the field of WS-Security, this accounts to message signing and
message decryption.
</para>
</formalpara>
<formalpara>
<title>Symmetric Keys</title>
<para>
Symmetric (or secret) keys are used for message encryption and decryption as well. The difference
being that both sides (sender and recipient) share the same, secret key.
</para>
</formalpara>
<formalpara>
<title>Trusted certificates</title>
<para>
These X509 certificates are called a <emphasis>trusted certificate</emphasis> because the keystore owner
trusts that the public key in the certificates indeed belong to the owner of the certificate. Within
WS-Security, these certificates are used for certificate validation, signature verification, and
encryption.
</para>
</formalpara>
<section>
<title>KeyTool</title>
<para>
Supplied with your Java Virtual Machine is the <command>keytool</command>, a key and certificate
management utility. You can use this tool to create new key stores, add new private keys and
certificates to them, etc. It is beyond the scope of this document to provide a full reference of
the <command>keytool</command> command, but you can find a reference <ulink
url="http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/keytool.html">
<citetitle>here</citetitle></ulink>, or by giving the command <prompt>keytool -help</prompt> on
the command line.
</para>
</section>
<section>
<title>KeyStoreFactoryBean</title>
<para>
To easily load a key store using Spring configuration, you can use the
<classname>KeyStoreFactoryBean</classname>. It has a resource location property, which you can set to
point to the path of the key store to load. A password may be given to check the integrity of the
key store data. If a password is not given, integrity checking is not performed.
</para>
<programlisting><![CDATA[
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="password" value="password"/>
<property name="location" value="classpath:org/springframework/ws/soap/security/xwss/test-keystore.jks"/>
</bean>]]></programlisting>
<caution>
<para>
If you don't specify the location property, a new, empty key store will be created, which is most
likely not what you want.
</para>
</caution>
</section>
<section id="security-key-store-callback-handler">
<title>KeyStoreCallbackHandler</title>
<para>
To use the key stores within a <classname>XwsSecurityInterceptor</classname>, you will need to define a
<classname>KeyStoreCallbackHandler</classname>. This callback has three properties with type key store:
(<methodname>keyStore</methodname>, <methodname>trustStore</methodname>, and
<methodname>symmetricStore</methodname>). The exact stores used by the handler depend on the
cryptographic operations that are to be performed by this handler. For private key operation, the
<methodname>keyStore</methodname> is used, for symmetric key operations the
<methodname>symmetricStore</methodname>, and for determining trust relationships, the
<methodname>trustStore</methodname>. The following table indicates this:
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Cryptographic operation</entry>
<entry>Key store used</entry>
</row>
</thead>
<tbody>
<row>
<entry>Certificate validation</entry>
<entry>
first the <methodname>keyStore</methodname>, then the
<methodname>trustStore</methodname>
</entry>
</row>
<row>
<entry>Decryption based on private key</entry>
<entry><methodname>keyStore</methodname></entry>
</row>
<row>
<entry>Decryption based on symmetric key</entry>
<entry><methodname>symmetricStore</methodname></entry>
</row>
<row>
<entry>Encryption based on public key certificate</entry>
<entry><methodname>trustStore</methodname></entry>
</row>
<row>
<entry>Encryption based on symmetric key</entry>
<entry><methodname>symmetricStore</methodname></entry>
</row>
<row>
<entry>Signing</entry>
<entry><methodname>keyStore</methodname></entry>
</row>
<row>
<entry>Signature verification</entry>
<entry><methodname>trustStore</methodname></entry>
</row>
</tbody>
</tgroup>
</informaltable>
Additionally, the <classname>KeyStoreCallbackHandler</classname> has a
<methodname>privateKeyPassword</methodname> property, which should be set to unlock the private key(s)
contained in the <methodname>keyStore</methodname>.
</para>
<para>
If the <methodname>symmetricStore</methodname> is not set, it will default to the
<methodname>keyStore</methodname>. If the key or trust store is not set, the callback handler will use
the standard Java mechanism to load or create it. Refer to the JavaDoc of the
<classname>KeyStoreCallbackHandler</classname> to know how this mechanism works.
</para>
<para>
For instance, if you want to use the <classname>KeyStoreCallbackHandler</classname> to validate incoming
certificates or signatures, you would use a trust store, like so:
<programlisting><![CDATA[
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="trustStore" ref="trustStore"/>
</bean>
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:truststore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>]]></programlisting>
If you want to use it to decrypt incoming certificates or sign outgoing messages, you would use a key
store, like so:
<programlisting><![CDATA[
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="keyStore"/>
<property name="privateKeyPassword" value="changeit"/>
</bean>
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:keystore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>]]></programlisting>
</para>
<para>
The following sections will indicate where the <classname>KeyStoreCallbackHandler</classname> can be
used, and which properties to set for particular cryptographic operations.
</para>
</section>
</section>
<section>
<title>Authentication</title>
<para>
As stated in the introduction, <emphasis>authentication</emphasis> is the task of determining whether a
principal is who they claim to be. Within WS-Security, authentication can take two forms: using a username
and password token (using either a plain text password or a password digest), or using a X509 certificate.
</para>
<section>
<title>Plain Text Username Authentication</title>
<para>
The simplest form of username authentication uses <emphasis>plain text passwords</emphasis>. In this
scenario, the SOAP message will contain a <literal>UsernameToken</literal> element, which itself
contains a <literal>Username</literal> element and a <literal>Password</literal> element which contains
the plain text password. Plain text authentication can be compared to the Basic Authentication provided
by HTTP servers.
</para>
<warning>
<para>
Note that plain text passwords are not very secure. Therefore, you should always add additional
security measures to your transport layer if you are using them (using HTTPS instead of plain HTTP,
for instance).
</para>
</warning>
<para>
To require that every incoming message contains a <literal>UsernameToken</literal> with a plain
text password, the security policy file should contain a <literal>RequireUsernameToken</literal>
element, with the <literal>passwordDigestRequired</literal> attribute set to <literal>false</literal>.
You can find a reference of possible child elements <ulink
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp567459">
<citetitle>here</citetitle></ulink>.
</para>
<programlisting><![CDATA[
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
...
<xwss:RequireUsernameToken passwordDigestRequired="false" nonceRequired="false"/>
...
</xwss:SecurityConfiguration>]]></programlisting>
<para>
If the username token is not present, the <classname>XwsSecurityInterceptor</classname> will return a
SOAP Fault to the sender. If it is present, it will fire a
<classname>PasswordValidationCallback</classname> with a <classname>PlainTextPasswordRequest</classname>
to the registered handlers. Within Spring-WS, there are three classes which handle this particular
callback.
</para>
<section id="security-simple-password-validation-callback-handler">
<title>SimplePasswordValidationCallbackHandler</title>
<para>
The simplest password validation handler is the
<classname>SimplePasswordValidationCallbackHandler</classname>. This handler validates passwords
against a in-memory <classname>Properties</classname> object, which you can specify using the
<methodname>users</methodname> property, like so:
</para>
<programlisting><![CDATA[
<bean id="passwordValidationHandler"
class="org.springframework.ws.soap.security.xwss.callback.SimplePasswordValidationCallbackHandler">
<property name="users">
<props>
<prop key="Bert">Ernie</prop>
</props>
</property>
</bean>]]></programlisting>
<para>
In this case, we are only allowing the user "Bert" to log in using the password "Ernie".
</para>
</section>
<section>
<title>AcegiPlainTextPasswordValidationCallbackHandler</title>
<para>
The <classname>AcegiPlainTextPasswordValidationCallbackHandler</classname> uses the excellent <ulink
url="http://acegisecurity.org/"><citetitle>Acegi Security Framework</citetitle></ulink> to
authenticate users. It is beyond the scope of this document to describe Acegi, but suffice it to say
that Acegi is a full-fledged security framework. You can read more about Acegi in the <ulink
url="http://acegisecurity.org/docbook/acegi.html"><citetitle>Acegi reference
documentation</citetitle></ulink>.
</para>
<para>
The <classname>AcegiPlainTextPasswordValidationCallbackHandler</classname> requires an Acegi
<classname>AuthenticationManager</classname> to operate. It uses this manager to authenticate against a
<classname>UsernamePasswordAuthenticationToken</classname> that it creates. If authentication is
successful, the token is stored in the <classname>SecurityContextHolder</classname>. You can set the
authentication manager using the <methodname>authenticationManager</methodname> property:
</para>
<programlisting><![CDATA[
<beans>
<bean id="acegiHandler"
class="org.springframework.ws.soap.security.xwss.callback.acegi.AcegiPlainTextPasswordValidationCallbackHandler">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<bean class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
</property>
</bean>
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
...
</beans>]]></programlisting>
</section>
<section>
<title>JaasPlainTextPasswordValidationCallbackHandler</title>
<para>
The <classname>JaasPlainTextPasswordValidationCallbackHandler</classname> is based on the standard
<ulink url="http://java.sun.com/products/jaas/"><citetitle>Java Authentication and Authorization
Service</citetitle></ulink>. It is beyond the scope of this document to provide a full
introduction into JAAS, but there is a <ulink
url="http://www.javaworld.com/javaworld/jw-09-2002/jw-0913-jaas.html">
<citetitle>good tutorial</citetitle></ulink> available.
</para>
<para>
The <classname>JaasPlainTextPasswordValidationCallbackHandler</classname> only requires a
<methodname>loginContextName</methodname> to operate. It creates a new JAAS
<classname>LoginContext</classname> using this name, and handles the standard JAAS
<classname>NameCallback</classname> and <classname>PasswordCallback</classname> using the username
and password provided in the SOAP message. This means that this callback handler
integrates with any JAAS
<classname>LoginModule</classname> that fires these callbacks during the
<methodname>login()</methodname> phase, which is standard behavior.
</para>
<para>
You can wire up a <classname>JaasPlainTextPasswordValidationCallbackHandler</classname> as follows:
</para>
<programlisting><![CDATA[
<bean id="jaasValidationHandler"
class="org.springframework.ws.soap.security.xwss.callback.jaas.JaasPlainTextPasswordValidationCallbackHandler">
<property name="loginContextName" value="MyLoginModule" />
</bean>]]></programlisting>
<para>
In this case, the callback handler uses the <classname>LoginContext</classname> named
"MyLoginModule". This module should be defined in your <filename>jaas.config</filename> file, as
explained in the abovementioned tutorial.
</para>
</section>
</section>
<section>
<title>Digest Username Authentication</title>
<para>
When using password digests, the SOAP message also contain a <literal>UsernameToken</literal> element,
which itself contains a <literal>Username</literal> element and a <literal>Password</literal> element.
The difference is that the password is not sent as plain text, but as a <emphasis>digest</emphasis>.The
recipient compares this digest to the digest he calculated from the known password of the user, and if
they are the same, the user is authenticated. It can be compared to the Digest
Authentication provided by HTTP servers.
</para>
<para>
To require that every incoming message contains a <literal>UsernameToken</literal> element with a
password digest, the security policy file should contain a <literal>RequireUsernameToken</literal>
element, with the <literal>passwordDigestRequired</literal> attribute set to <literal>true</literal>.
Additionally, the <literal>nonceRequired</literal> should be set to <literal>true</literal>:
You can find a reference of possible child elements <ulink
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp567459">
<citetitle>here</citetitle></ulink>.
</para>
<programlisting><![CDATA[
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
...
<xwss:RequireUsernameToken passwordDigestRequired="true" nonceRequired="true"/>
...
</xwss:SecurityConfiguration>]]></programlisting>
<para>
If the username token is not present, the <classname>XwsSecurityInterceptor</classname> will return a
SOAP Fault to the sender. If it is present, it will fire a
<classname>PasswordValidationCallback</classname> with a <classname>DigestPasswordRequest</classname>
to the registered handlers. Within Spring-WS, there are two classes which handle this particular
callback.
</para>
<section>
<title>SimplePasswordValidationCallbackHandler</title>
<para>
The <classname>SimplePasswordValidationCallbackHandler</classname> can handle both plain text
passwords as well as password digests. It is described in <xref
linkend="security-simple-password-validation-callback-handler"/>.
</para>
</section>
<section>
<title>AcegiDigestPasswordValidationCallbackHandler</title>
<para>
The <classname>AcegiPlainTextPasswordValidationCallbackHandler</classname> requires an Acegi
<classname>UserDetailService</classname> to operate. It uses this service to retrieve the password
of the user specified in the token. The digest of the password contained in this details object is
then compared with the digest in the message. If they are equal, the user has succesfully
authenticated, and a <classname>UsernamePasswordAuthenticationToken</classname> is stored in the
<classname>SecurityContextHolder</classname>. You can set the service using the
<methodname>userDetailsService</methodname>. Additionally, you can set a
<methodname>userCache</methodname> property, to cache loaded user details.
</para>
<programlisting><![CDATA[
<beans>
<bean class="org.springframework.ws.soap.security.xwss.callback.acegi.AcegiDigestPasswordValidationCallbackHandler">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
...
</beans>]]></programlisting>
</section>
</section>
<section id="security-certificate-authentication">
<title>Certificate Authentication</title>
<para>
A more secure way of authentication uses X509 certificates. In this scenerario, the SOAP message
contains a <literal>BinarySecurityToken</literal>, which contains a Base 64-encoded version of a X509
certificate. The recipient is used by the recipient to authenticate. The certificate stored in the
message is also used to sign the message (see <xref linkend="security-verifying-signatures"/>).
</para>
<para>
To make sure that all incoming SOAP messages carry a <literal>BinarySecurityToken</literal>, the
security policy file should contain a <literal>RequireSignature</literal> element. This element can
carry further other elements, which will be covered in <xref linkend="security-verifying-signatures"/>.
You can find a reference of possible child elements <ulink
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565769">
<citetitle>here</citetitle></ulink>.
</para>
<programlisting><![CDATA[
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
...
<xwss:RequireSignature requireTimestamp="false">
...
</xwss:SecurityConfiguration>]]></programlisting>
<para>
When a message arrives that carries no certificate, the <classname>XwsSecurityInterceptor</classname>
will return a SOAP Fault to the sender. If it is present, it will fire a
<classname>CertificateValidationCallback</classname>. There are three handlers within Spring-WS
which handle this callback for authentication purposes.
</para>
<note>
<para>
In most cases, certificate <emphasis>authentication</emphasis> should be preceded by certificate
<emphasis>validation</emphasis>, since you only want authenticate against valid certificates.
Invalid certificates such as certificates for which the expiration date has passed, or which are not
in your store of trusted certificates, should be ignored.
</para>
<para>
In Spring-WS terms, this means that the
<classname>AcegiCertificateValidationCallbackHandler</classname> or
<classname>JaasCertificateValidationCallbackHandler</classname> should be preceded by
<classname>KeyStoreCallbackHandler</classname>. This can be accomplished by setting the order of the
<methodname>callbackHandlers</methodname> property in the configuration of the
<classname>XwsSecurityInterceptor</classname>:
<programlisting><![CDATA[
<bean id="wsSecurityInterceptor"
class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
<property name="policyConfiguration" value="classpath:securityPolicy.xml"/>
<property name="callbackHandlers">
<list>
<ref bean="keyStoreHandler"/>
<ref bean="acegiHandler"/>
</list>
</property>
</bean>
]]></programlisting>
Using this setup, the interceptor will first determine if the certificate in the message is valid
using the keystore, and then authenticate against it.
</para>
</note>
<section>
<title>KeyStoreCallbackHandler</title>
<para>
The <classname>KeyStoreCallbackHandler</classname> uses a standard Java key store to validate
certificates. This certificate validation process consists of the following steps:
<orderedlist>
<listitem>
<para>
First, the handler will check whether the certificate is in the private
<methodname>keyStore</methodname>. If it is, it is valid.
</para>
</listitem>
<listitem>
<para>
If the certificate is not in the private key store, the handler will check whether the
the current date and time are within the validity period given in the certificate.
If they are not, the certificate is invalid; if it is, it will continue with the final
step.
</para>
</listitem>
<listitem>
<para>
Finally, a <emphasis>certification path</emphasis> for the certificate is created. This
basically means that the handler will determine whether the certificate has been issued
by any of the certificate authorities in the <methodname>trustStore</methodname>. If it
a certification path can be built succesfully, the certificate is valid. Otherwise, it
is not.
</para>
</listitem>
</orderedlist>
</para>
<para>
To use the <classname>KeyStoreCallbackHandler</classname> for certificate validation purposes, you
will most likely only set the <methodname>trustStore</methodname> property:
<programlisting><![CDATA[
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="trustStore" ref="trustStore"/>
</bean>
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:truststore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>]]></programlisting>
Using this setup, the certificate that is to be validated must either be in the trust store itself,
or the trust store must contain a certificate authority that issued the certificate.
</para>
</section>
<section>
<title>AcegiCertificateValidationCallbackHandler</title>
<para>
The <classname>AcegiCertificateValidationCallbackHandler</classname> requires an Acegi
<classname>AuthenticationManager</classname> to operate. It uses this manager authenticate against a
<classname>X509AuthenticationToken</classname> that it creates. The configured authentication
manager is expected to supply a provider which can handle this token (usually an instance of
<classname>X509AuthenticationProvider</classname>). If authentication is succesfull, the token is
stored in the <classname>SecurityContextHolder</classname>. You can set the authentication manager
using the <methodname>authenticationManager</methodname> property:
</para>
<programlisting><![CDATA[
<beans>
<bean id="acegiCertificateHandler"
class="org.springframework.ws.soap.security.xwss.callback.acegi.AcegiCertificateValidationCallbackHandler">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="authenticationManager"
class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<bean class="org.acegisecurity.providers.x509.X509AuthenticationProvider">
<property name="x509AuthoritiesPopulator">
<bean class="org.acegisecurity.providers.x509.populator.DaoX509AuthoritiesPopulator">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
</property>
</bean>
</property>
</bean>
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
...
</beans>]]></programlisting>
<para>
In this case, we are using a custom user details service to obtain authentication details based on
the certificate. Refer to the <ulink
url="http://acegisecurity.org/docbook/acegi.html"><citetitle>Acegi reference
documentation</citetitle></ulink> for more information about authentication against X509
certificates.
</para>
</section>
<section>
<title>JaasCertificateValidationCallbackHandler</title>
<para>
The <classname>JaasCertificateValidationCallbackHandler</classname> requires a
<methodname>loginContextName</methodname> to operate. It creates a new JAAS
<classname>LoginContext</classname> using this name and with the
<classname>X500Principal</classname> of the certificate. This means that this callback handler
integrates with any JAAS <classname>LoginModule</classname> that handles X500 principals.
</para>
<para>
You can wire up a <classname>JaasCertificateValidationCallbackHandler</classname> as follows:
</para>
<programlisting><![CDATA[
<bean id="jaasValidationHandler"
class="org.springframework.ws.soap.security.xwss.callback.jaas.JaasCertificateValidationCallbackHandler">
<property name="loginContextName">MyLoginModule</property>
</bean>]]></programlisting>
<para>
In this case, the callback handler uses the <classname>LoginContext</classname> named
"MyLoginModule". This module should be defined in your <filename>jaas.config</filename> file, and
should be able to authenticate against X500 principals.
</para>
</section>
</section>
</section>
<section>
<title>Digital Signatures</title>
<para>
The <emphasis>digital signature</emphasis> of a message is a piece of information based on both the document
and the signer's private key. There are two main tasks related to signatures in WS-Security: verifying
signatures and signing messages.
</para>
<section id="security-verifying-signatures">
<title>Verifying Signatures</title>
<para>
Just like <link linkend="security-certificate-authentication">certificate-based authentication</link>,
a signed message contains a <literal>BinarySecurityToken</literal>, which contains the certificate used
to sign the message. Additionally, it contains a <literal>SignedInfo</literal> block, which indicates
what part of the message was signed.
</para>
<para>
To make sure that all incoming SOAP messages carry a <literal>BinarySecurityToken</literal>, the
security policy file should contain a <literal>RequireSignature</literal> element.
It can also contain a <literal>SignatureTarget</literal> element, which specifies the target message
part which was expected to be signed, and various other subelements. You can also define the private key
alias to use, whether to use a symmetric instead of a private key, and many other properties. You can
find a reference of possible child elements <ulink
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565769">
<citetitle>here</citetitle></ulink>.
</para>
<programlisting><![CDATA[
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireSignature requireTimestamp="false"/>
</xwss:SecurityConfiguration>]]></programlisting>
<para>
If the signature is not present, the <classname>XwsSecurityInterceptor</classname> will return a
SOAP Fault to the sender. If it is present, it will fire a
<classname>SignatureVerificationKeyCallback</classname> to the registered handlers. Within Spring-WS,
there are is one class which handles this particular callback: the
<classname>KeyStoreCallbackHandler</classname>.
</para>
<section>
<title>KeyStoreCallbackHandler</title>
<para>
As described in <xref linkend="security-key-store-callback-handler"/>, the
<classname>KeyStoreCallbackHandler</classname> uses a <classname>java.security.KeyStore</classname>
for handling various cryptographic callbacks, including signature verification. For signature
verification, the handler uses the <methodname>trustStore</methodname> property:
</para>
<programlisting><![CDATA[
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="trustStore" ref="trustStore"/>
</bean>
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:org/springframework/ws/soap/security/xwss/test-truststore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>]]></programlisting>
</section>
</section>
<section>
<title>Signing Messages</title>
<para>
When signing a message, the <classname>XwsSecurityInterceptor</classname> adds the
<literal>BinarySecurityToken</literal> to the message, and a <literal>SignedInfo</literal> block, which
indicates what part of the message was signed.
</para>
<para>
To sign all outgoing SOAP messages, the
security policy file should contain a <literal>Sign</literal> element.
It can also contain a <literal>SignatureTarget</literal> element, which specifies the target message
part which was expected to be signed, and various other subelements. You can also define the private key
alias to use, whether to use a symmetric instead of a private key, and many other properties. You can
find a reference of possible child elements <ulink
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565497">
<citetitle>here</citetitle></ulink>.
</para>
<programlisting><![CDATA[
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:Sign includeTimestamp="false" />
</xwss:SecurityConfiguration>]]></programlisting>
<para>
The <classname>XwsSecurityInterceptor</classname> will fire a
<classname>SignatureKeyCallback</classname> to the registered handlers. Within Spring-WS,
there are is one class which handles this particular callback: the
<classname>KeyStoreCallbackHandler</classname>.
</para>
<section>
<title>KeyStoreCallbackHandler</title>
<para>
As described in <xref linkend="security-key-store-callback-handler"/>, the
<classname>KeyStoreCallbackHandler</classname> uses a <classname>java.security.KeyStore</classname>
for handling various cryptographic callbacks, including signing messages. For adding signatures,
the handler uses the <methodname>keyStore</methodname> property. Additionally, you must set
the <methodname>privateKeyPassword</methodname> property to unlock the private key used for signing.
</para>
<programlisting><![CDATA[
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="keyStore"/>
<property name="privateKeyPassword" value="changeit"/>
</bean>
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:keystore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>]]></programlisting>
</section>
</section>
</section>
<section>
<title>Encryption and Decryption</title>
<para>
When <emphasis>encrypting</emphasis>, the message is transformed into a form that can only be read with the
appropriate key. The message can be <emphasis>decrypted</emphasis> to reveal the original, readable message.
</para>
<section>
<title>Decryption</title>
<para>
To decrypt incoming SOAP messages, the security policy file should contain a
<literal>RequireEncryption</literal> element. This element can further carry a
<literal>EncryptionTarget</literal> element which indicates which part of the message should be
encrypted, a <literal>SymmetricKey</literal> to indicate that a shared secret instead of the regular
private key should be used to decrypt the message. You can read a description of the other elements
<ulink url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565951">
<citetitle>here</citetitle></ulink>.
</para>
<programlisting><![CDATA[
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireEncryption />
</xwss:SecurityConfiguration>]]></programlisting>
<para>
If an incoming message is not encrypted, the <classname>XwsSecurityInterceptor</classname> will return a
SOAP Fault to the sender. If it is present, it will fire a <classname>DecryptionKeyCallback</classname>
to the registered handlers. Within Spring-WS, there is one class which handled this particular callback:
the <classname>KeyStoreCallbackHandler</classname>.
</para>
<section>
<title>KeyStoreCallbackHandler</title>
<para>
As described in <xref linkend="security-key-store-callback-handler"/>, the
<classname>KeyStoreCallbackHandler</classname> uses a <classname>java.security.KeyStore</classname>
for handling various cryptographic callbacks, including decryption. For decryption,
the handler uses the <methodname>keyStore</methodname> property. Additionally, you must set
the <methodname>privateKeyPassword</methodname> property to unlock the private key used for
decryption. For decryption based on symmetric keys, it will use the
<methodname>symmetricStore</methodname>.
</para>
<programlisting><![CDATA[
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="keyStore"/>
<property name="privateKeyPassword" value="changeit"/>
</bean>
<bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:keystore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>]]></programlisting>
</section>
</section>
<section>
<title>Encryption</title>
<para>
To encrypt outgoing SOAP messages, the security policy file should contain a <literal>Encrypt</literal>
element. This element can further carry a <literal>EncryptionTarget</literal> element which indicates
which part of the message should be encrypted, a <literal>SymmetricKey</literal> to indicate that a
shared secret instead of the regular private key should be used to decrypt the message. You can read a
description of the other elements <ulink
url="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565951">
<citetitle>here</citetitle></ulink>.
</para>
<programlisting><![CDATA[
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:Encrypt />
</xwss:SecurityConfiguration>]]></programlisting>
<para>
The <classname>XwsSecurityInterceptor</classname> will fire a
<classname>EncryptionKeyCallback</classname> to the registered handlers in order to retrieve the
encryption information. Within Spring-WS, there is one class which handled this particular callback: the
<classname>KeyStoreCallbackHandler</classname>.
</para>
<section>
<title>KeyStoreCallbackHandler</title>
<para>
As described in <xref linkend="security-key-store-callback-handler"/>, the
<classname>KeyStoreCallbackHandler</classname> uses a <classname>java.security.KeyStore</classname>
for handling various cryptographic callbacks, including encryption. For encryption based on public
keys, the handler uses the <methodname>trustStore</methodname> property. For encryption based on
symmetric keys, it will use the <methodname>symmetricStore</methodname>.
</para>
<programlisting><![CDATA[
<beans>
<bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="trustStore" ref="trustStore"/>
</bean>
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:truststore.jks"/>
<property name="password" value="changeit"/>
</bean>
</beans>]]></programlisting>
</section>
</section>
</section>
</chapter>

345
src/docbkx/server.xml Normal file
View File

@@ -0,0 +1,345 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="ws">
<title>Creating a Web service with Spring-WS</title>
<section id="web-service-messages">
<title>Web service messages</title>
<section>
<title>
<interfacename>WebServiceMessage</interfacename> and <interfacename>SoapMessage</interfacename>
</title>
<para>
One of the core interfaces within Spring Web Services is the
<interfacename>WebServiceMessage</interfacename>. This interface represents a protocol agnostic XML
message. The interface contains methods that provide access to the payload of the message, in the form
of a <interfacename>javax.xml.transform.Source</interfacename> or a
<interfacename>javax.xml.transform.Result</interfacename>. <interfacename>Source</interfacename> and
<interfacename>Result</interfacename> are tagging interfaces that represent an abstraction over XML
input and output. Concrete implementations wrap various XML representations, as indicated in the table
below.
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Source/Result implementation</entry>
<entry>Wraps XML representation</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<classname>javax.xml.transform.dom.DOMSource</classname>
</entry>
<entry>
<interfacename>org.w3c.dom.Node</interfacename>
</entry>
</row>
<row>
<entry>
<classname>javax.xml.transform.dom.DOMResult</classname>
</entry>
<entry>
<interfacename>org.w3c.dom.Node</interfacename>
</entry>
</row>
<row>
<entry>
<classname>javax.xml.transform.sax.SAXSource</classname>
</entry>
<entry>
<classname>org.xml.sax.InputSource</classname>
and
<interfacename>org.xml.sax.XMLReader</interfacename>
</entry>
</row>
<row>
<entry>
<classname>javax.xml.transform.sax.SAXResult</classname>
</entry>
<entry>
<interfacename>org.xml.sax.ContentHandler</interfacename>
</entry>
</row>
<row>
<entry>
<classname>javax.xml.transform.stream.StreamSource</classname>
</entry>
<entry>
<classname>java.io.File</classname>, <classname>java.io.InputStream</classname>, or
<classname>java.io.Reader</classname>
</entry>
</row>
<row>
<entry>
<classname>javax.xml.transform.stream.StreamResult</classname>
</entry>
<entry>
<classname>java.io.File</classname>, <classname>java.io.OutputStream</classname>, or
<classname>java.io.Writer</classname>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
In addition to reading from and writing to the payload, a Web service message can write itself to an
output stream.
</para>
<para>
The <interfacename>SoapMessage</interfacename> is an extension of
<interfacename>WebServiceMessage</interfacename>. It contains SOAP-specific methods, such as getting
SOAP Headers, SOAP Faults, etc. Generally, your code should only not be dependent on
<interfacename>SoapMessage</interfacename>, because the content of the SOAP Body can be obtained via
<methodname>getPayloadSource()</methodname> and <methodname>getPayloadResult()</methodname> in the
<interfacename>WebServiceMessage</interfacename>. Only when it is necessary to perform SOAP-specific
actions, such as adding a header, get an attachment, etc., should you need to cast
<interfacename>WebServiceMessage</interfacename> to <interfacename>SoapMessage</interfacename>.
</para>
</section>
<section id="message-factories">
<title>Message Factories</title>
<para>
Concrete message implementation are created by a
<interfacename>WebServiceMessageFactory</interfacename>. This factory can create an empty message, or
read a message based on an input stream.
There are two concrete implementations of <interfacename>WebServiceMessageFactory</interfacename>.
One is based on SAAJ, the SOAP with Attachments API for Java, the other based on Axis 2's AXIOM, the
AXis Object Model.
</para>
<section>
<title><classname>SaajSoapMessageFactory</classname></title>
<para>
The <classname>SaajSoapMessageFactory</classname> uses the SOAP with Attachments API for Java to
create <classname>SoapMessage</classname> implementations. SAAJ is part of J2EE 1.4, so it should be
supported under most modern application servers. You wire up a
<classname>SaajSoapMessageFactory</classname> like so:
<programlisting><![CDATA[
<bean id="messageFactory"
class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />
]]></programlisting>
</para>
<note>
<para>
SAAJ is based on DOM, the Document Object Model. This means that all SOAP messages are
stored in memory as a whole. For larger SOAP messages, this may not be very performant.
In that case, the <classname>AxiomSoapMessageFactory</classname> might be more applicable.
</para>
</note>
</section>
<section>
<title><classname>AxiomSoapMessageFactory</classname></title>
<para>
The <classname>AxiomSoapMessageFactory</classname> uses the AXis 2 Object Model to create
<interfacename>SoapMessage</interfacename> implementations. AXIOM uses StAX, the Streaming API for
XML. StAX provides a pull-based mechanism for reading XML messages, which can be more efficient
for larger messages.
</para>
<para>
To increase reading performance on the <classname>AxiomSoapMessageFactory</classname>,
you can set the <property>payloadCaching</property> property to false (default is true).
This this will read the contents of the SOAP body directly from the stream.
When this setting is enabled, the payload can only be read once.
This means that you have to make sure that any preprocessing of the message does not consume it.
</para>
<para>
You use the <classname>AxiomSoapMessageFactory</classname> as follows:
<programlisting><![CDATA[
<bean id="messageFactory"
class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
<property name="payloadCaching" value="true"/>
</bean>]]></programlisting>
</para>
</section>
</section>
</section>
<!--
<section id="ws-introduction">
<title>Introduction</title>
<para>
Spring's Web service framework is designed around
</para>
</section>
<section>
<title>MessageDispatcher</title>
<para>
Spring-WS is designed around a central dispatching mechanism, which received and forwards incoming
</para>
</section>
<section>
<title>Endpoints</title>
</section>
<section id="ws-endpoint-mapping">
<title>Endpoint mappings</title>
<para>
The endpoint mapping is responsible for mapping incoming messages to appropriate endpoints. It does this by
delivering a <classname>EndpointInterceptorChain</classname>, which consists of the endpoint that matches
the incoming request, and an optional list of endpoint interceptors. When a message is received by the
<classname>MessageDispatcher</classname>, it will ask the registered endpoint mappings to come up with a
appropriate <classname>HandlerExecutionChain</classname>. After that, the
<classname>MessageDispatcher</classname> will invoke the endpoint and interceptors in the chain.
</para>
<para>
Most endpoint mappings inherit from the <classname>AbstractEndpointMapping</classname>, which offers the
following properties:
<informaltable>
<tgroup cols="2">
<tbody>
<row>
<entry>
<methodname>interceptors</methodname>
</entry>
<entry>
the list of interceptors use. <interfacename>EndpointInterceptor</interfacename>s are
discussed in <xref linkend="ws-endpoint-interceptor"/>.
</entry>
</row>
<row>
<entry>
<methodname>defaultHandler</methodname>
</entry>
<entry>
the default handler to use. This endpoint will be returned if no specific mapping was
found.
</entry>
</row>
<row>
<entry>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<section>
<title>SoapActionEndpointMapping</title>
</section>
<section>
<title>PayloadRootQNameEndpointMapping</title>
</section>
<section id="ws-endpoint-interceptor">
<title>Adding <interfacename>EndpointInterceptors</interfacename></title>
</section>
<section>
<title>Handling Exceptions</title>
<para>
Spring-WS provides
<classname>EndpointExceptionResolvers</classname>
to ease the pain of unexpected
exceptions occurring while your message is being processed by an endpoint which matched the request.
<classname>EndpointExceptionResolver</classname>
s somewhat resemble the exception mappings that can be
defined in the web application descriptor
<filename>web.xml</filename>
.
Rather than expose the innards of your application by giving a client a full stack trace, you can handle
the exception any way you want, e.g. return a SOAP fault with a specific fault code and string.
Furthermore, a programmatic way of handling exceptions gives you many more options for how to respond
appropriately.
</para>
<para>
Besides implementing the
<classname>HandlerExceptionResolver</classname>
interface, which is only a
matter of implementing the
<methodname>resolveException(MessageContext, endpoint, Exception)</methodname>
method and returning a
boolean, you may also use the
<classname>SoapFaultMappingExceptionResolver</classname>
.
This resolver enables you to take the class name of any exception that might be thrown and map it to a
SOAP Fault, like so:
<programlisting><![CDATA[
<bean id="exceptionResolver"
class="org.springframework.ws.soap.endpoint.SoapFaultMappingExceptionResolver">
<property name="defaultFault" value="RECEIVER,Server error">
</property>
<property name="exceptionMappings">
<props>
<prop key="org.springframework.oxm.ValidationFailureException">
SENDER,Invalid request
</prop>
</props>
</property>
</bean>
]]></programlisting>
This configuration will map exceptions of type
<classname>ValidationFailureException</classname>
to a
sender side SOAP Fault with a fault string "Invalid request".
If any other exception occurs, it will return the default fault: a server side fault with fault string
"Server error".
Refer to the Javadoc of
<classname>SoapFaultDefinitionEditor</classname>
to read more about the exact
notation of the faults.
</para>
</section>
</section>
<section>
<title>Similarities between Spring-MVC and Spring-WS</title>
<para>
Spring-WS has the same basic architecture as Spring's Web MVC framework.
The table below shows some of the core concepts of Spring Web MVC, and the corresponding class in Spring-WS.
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Spring Web MVC</entry>
<entry>Spring Web Services</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<classname>DispatcherServlet</classname>
</entry>
<entry>
<classname>MessageDispatcher</classname>
</entry>
</row>
<row>
<entry>handler</entry>
<entry>endpoint</entry>
</row>
<row>
<entry>
<classname>HandlerAdapter</classname>
</entry>
<entry>
<classname>EndpointAdapter</classname>
</entry>
</row>
<row>
<entry>
<classname>HandlerMapping</classname>
</entry>
<entry>
<classname>EndpointMapping</classname>
</entry>
</row>
<row>
<entry>
<classname>HandlerInterceptor</classname>
</entry>
<entry>
<classname>EndpointInterceptor</classname>
</entry>
</row>
<row>
<entry>
<classname>HandlerExceptionResolver</classname>
</entry>
<entry>
<classname>EndpointExceptionResolver</classname>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</section>
-->
</chapter>