Moved documentation from separate module into the main module, so that it is published with the site.
This commit is contained in:
@@ -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
72
pom.xml
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
58
src/docbkx/bibliography.xml
Normal file
58
src/docbkx/bibliography.xml
Normal 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
160
src/docbkx/client.xml
Normal 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
46
src/docbkx/index.xml
Normal 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
142
src/docbkx/overview.xml
Normal 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 service’s 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
709
src/docbkx/oxm.xml
Normal 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
22
src/docbkx/preface.xml
Normal 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>
|
||||
421
src/docbkx/resources/css/html.css
Normal file
421
src/docbkx/resources/css/html.css
Normal 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;
|
||||
}
|
||||
BIN
src/docbkx/resources/images/i21-banner-rhs.jpg
Normal file
BIN
src/docbkx/resources/images/i21-banner-rhs.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
src/docbkx/resources/images/oxm-exceptions.png
Normal file
BIN
src/docbkx/resources/images/oxm-exceptions.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
48
src/docbkx/resources/images/oxm-exceptions.svg
Normal file
48
src/docbkx/resources/images/oxm-exceptions.svg
Normal 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->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->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->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->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 |
BIN
src/docbkx/resources/images/xdev-spring_logo.jpg
Normal file
BIN
src/docbkx/resources/images/xdev-spring_logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
470
src/docbkx/resources/xsl/fopdf.xsl
Normal file
470
src/docbkx/resources/xsl/fopdf.xsl
Normal 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 © 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>
|
||||
91
src/docbkx/resources/xsl/html.xsl
Normal file
91
src/docbkx/resources/xsl/html.xsl
Normal 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>
|
||||
208
src/docbkx/resources/xsl/html_chunk.xsl
Normal file
208
src/docbkx/resources/xsl/html_chunk.xsl
Normal 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) > 0
|
||||
or count($up) > 0
|
||||
or count($next) > 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> </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> | </xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
<xsl:otherwise> </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> </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> </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> </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
890
src/docbkx/security.xml
Normal 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
345
src/docbkx/server.xml
Normal 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>
|
||||
Reference in New Issue
Block a user