Moved documentation to parent module
This commit is contained in:
@@ -1,58 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,160 +0,0 @@
|
||||
<?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>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
@@ -1,48 +0,0 @@
|
||||
<?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>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB |
@@ -1,46 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,142 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,617 +0,0 @@
|
||||
<?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/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>
|
||||
@@ -1,22 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,890 +0,0 @@
|
||||
<?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>
|
||||
|
||||
@@ -1,345 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,466 +0,0 @@
|
||||
<?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:external-graphic src="file:src/dockbx/images/logo.jpg"/>
|
||||
</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>
|
||||
@@ -1,290 +0,0 @@
|
||||
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: 12px;
|
||||
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: 12px;
|
||||
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: 1px black;
|
||||
empty-cells: hide;
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table[summary^="Note"],
|
||||
table[summary^="Warning"],
|
||||
table[summary^="Tip"] {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
border: 1px black;
|
||||
empty-cells: hide;
|
||||
margin: 10px 0px 10px -20px;
|
||||
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;
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,205 +0,0 @@
|
||||
<?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>
|
||||
Reference in New Issue
Block a user