DATAJPA-3 - Initial port of Hades reference documentation.

- created Docbook setup (copied from Document project)
- split up Hades documentation into parts and left out what's currently not relevant (extensions, IDE plugin)
- removed sample application part for now
- clearly separated documentation of the general repository implementation from JPA specifics (use the one from Spring Data Commons)
- extracted general namespace configuration into Spring Data Commons
- updated project metadata (repositories, source repo, homepage)
This commit is contained in:
Oliver Gierke
2010-12-23 20:04:53 +01:00
parent a005f0bd6e
commit 8d2845c606
62 changed files with 3821 additions and 0 deletions

59
pom.xml
View File

@@ -168,6 +168,65 @@
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId>
<version>2.0.7</version>
<executions>
<execution>
<goals>
<goal>generate-html</goal>
<goal>generate-pdf</goal>
</goals>
<phase>pre-site</phase>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.docbook</groupId>
<artifactId>docbook-xml</artifactId>
<version>4.4</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<configuration>
<includes>index.xml</includes>
<xincludeSupported>true</xincludeSupported>
<foCustomization>${project.basedir}/src/docbkx/resources/xsl/fopdf.xsl</foCustomization>
<htmlStylesheet>css/html.css</htmlStylesheet>
<chunkedOutput>false</chunkedOutput>
<htmlCustomization>${project.basedir}/src/docbkx/resources/xsl/html.xsl</htmlCustomization>
<useExtensions>1</useExtensions>
<highlightSource>1</highlightSource>
<highlightDefaultLanguage></highlightDefaultLanguage>
<!-- callouts -->
<entities>
<entity>
<name>version</name>
<value>${pom.version}</value>
</entity>
</entities>
<postProcess>
<copy todir="${project.basedir}/target/site/reference">
<fileset dir="${project.basedir}/target/docbkx">
<include name="**/*.html" />
<include name="**/*.pdf" />
</fileset>
</copy>
<copy todir="${project.basedir}/target/site/reference/html">
<fileset dir="${project.basedir}/src/docbkx/resources">
<include name="**/*.css" />
<include name="**/*.png" />
<include name="**/*.gif" />
<include name="**/*.jpg" />
</fileset>
</copy>
<move file="${project.basedir}/target/site/reference/pdf/index.pdf"
tofile="${project.basedir}/target/site/reference/pdf/${project.artifactId}-reference.pdf"
failonerror="false" />
</postProcess>
</configuration>
</plugin>
</plugins>
</build>

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<appendix id="faq">
<title>Frequently asked questions</title>
<qandaset>
<qandadiv>
<title>Common</title>
<qandaentry>
<question>
<para>I'd like to get more detailled logging information on what
methods are called inside
<interfacename>JpaRepository</interfacename>, e.g. How can I gain
them?</para>
</question>
<answer>
<para>You can make use of
<classname>CustomizableTraceInterceptor</classname> provided by
Spring:</para>
<programlisting language="xml">&lt;bean id="customizableTraceInterceptor" class="
org.springframework.aop.interceptor.CustomizableTraceInterceptor"&gt;
&lt;property name="enterMessage" value="Entering $[methodName]($[arguments])"/&gt;
&lt;property name="exitMessage" value="Leaving $[methodName](): $[returnValue]"/&gt;
&lt;/bean&gt;
&lt;aop:config&gt;
&lt;aop:advisor advice-ref="customizableTraceInterceptor"
pointcut="execution(public * org.sfw.data.jpa.repository.JpaRepository+.*(..))"/&gt;
&lt;/aop:config&gt;</programlisting>
</answer>
</qandaentry>
</qandadiv>
<qandadiv>
<title>Infrastructure</title>
<qandaentry>
<question>
<para>Currently I have implemented a repository layer based on
<classname>HibernateDaoSupport</classname>. I create a
<classname>SessionFactory</classname> by using Spring's
<classname>AnnotationSessionFactoryBean</classname>. How do I get
Hades DAOs working in this environment.</para>
</question>
<answer>
<para>You have to replace
<classname>AnnotationSessionFactoryBean</classname> with the
<classname>LocalContainerEntityManagerFactoryBean</classname>.
Supposed you have registered it under
<code>entityManagerFactory</code> you can reference it in you
repositories based on <classname>HibernateDaoSupport</classname> as
follows:</para>
<example>
<title>Looking up a SessionFactory from an
HibernateEntityManagerFactory</title>
<programlisting language="xml">&lt;bean class="com.acme.YourDaoBasedOnHibernateDaoSupport"&gt;
&lt;property name="sessionFactory"&gt;
&lt;bean factory-bean="entityManagerFactory"
factory-method="getSessionFactory" /&gt;
&lt;/property&gt;
&lt;/bean&gt;</programlisting>
</example>
</answer>
</qandaentry>
</qandadiv>
<qandadiv>
<title>Auditing</title>
<qandaentry>
<question>
<para>I want to use Spring Data JPA auditing capabilities but have
my database already set up to set modification and creation date on
entities. How to prevent Hades to set the date
programmatically.</para>
</question>
<answer>
<para>Just use the <code>set-dates</code> attribute of the
<code>auditing</code> namespace element to false.</para>
</answer>
</qandaentry>
</qandadiv>
</qandaset>
</appendix>

View File

@@ -0,0 +1,114 @@
<?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">
<glossary id="glossary">
<glossdiv>
<title>A</title>
<glossentry>
<glossterm>AOP</glossterm>
<glossdef>
<para>Aspect oriented programming</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv>
<title>C</title>
<glossentry>
<glossterm>Commons DBCP</glossterm>
<glossdef>
<para>Commons DataBase Connection Pools - Library of the Apache
foundation offering pooling implementations of the
<interfacename>DataSource</interfacename> interface.</para>
</glossdef>
</glossentry>
<glossentry>
<glossterm>CRUD</glossterm>
<glossdef>
<para>Create, Read, Update, Delete - Basic persistence
operations</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv>
<title>D</title>
<glossentry>
<glossterm>DAO</glossterm>
<glossdef>
<para>Data Access Object - Pattern to separate persisting logic from
the object to be persisted</para>
</glossdef>
</glossentry>
<glossentry>
<glossterm>Dependency Injection</glossterm>
<glossdef>
<para>Pattern to hand a component's dependency to the component from
outside, freeing the component to lookup the dependant itself. For
more information see <ulink
url="http://en.wikipedia.org/wiki/Dependency_Injection">http://en.wikipedia.org/wiki/Dependency_Injection</ulink>.</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv>
<title>E</title>
<glossentry>
<glossterm>EclipseLink</glossterm>
<glossdef>
<para>Object relational mapper implementing JPA - <ulink
url="http://www.eclipselink.org">http://www.eclipselink.org</ulink></para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv>
<title>H</title>
<glossentry>
<glossterm>Hibernate</glossterm>
<glossdef>
<para>Object relational mapper implementing JPA - <ulink
url="http://www.hibernate.org">http://www.hibernate.org</ulink></para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv>
<title>J</title>
<glossentry>
<glossterm>JPA</glossterm>
<glossdef>
<para>Java Persistence Api</para>
</glossdef>
</glossentry>
</glossdiv>
<glossdiv>
<title>S</title>
<glossentry>
<glossterm>Spring</glossterm>
<glossdef>
<para>Java application framework - <ulink
url="http://www.springframework.org">http://www.springframework.org</ulink></para>
</glossdef>
</glossentry>
</glossdiv>
</glossary>

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

@@ -0,0 +1,77 @@
<?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 Data JPA - Reference Documentation</title>
<releaseinfo>1.0.0.BUILD-SNAPSHOT</releaseinfo>
<authorgroup>
<author>
<firstname>Oliver</firstname>
<surname>Gierke</surname>
<affiliation>
<jobtitle>Senior Consultant</jobtitle>
<orgname>SpringSource - a division of VMware</orgname>
</affiliation>
<email>ogierke@vmware.com</email>
</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>
<pubdate />
<copyright>
<year>2008-2011</year>
<holder>The original authors</holder>
</copyright>
<revhistory>
<revision>
<date>09.02.2011</date>
<author>
<firstname>Oliver</firstname>
<surname>Gierke</surname>
</author>
<revremark>Initial port from Hades documentation</revremark>
</revision>
</revhistory>
</bookinfo>
<toc />
<xi:include href="preface.xml" />
<part id="reference">
<title>Reference Documentation</title>
<xi:include href="https://github.com/SpringSource/spring-data-commons/raw/master/src/docbkx/repositories.xml" />
<xi:include href="reference/jpa.xml" />
</part>
<part id="appendix">
<title>Appendix</title>
<xi:include href="https://github.com/SpringSource/spring-data-commons/raw/master/src/docbkx/repository-namespace-reference.xml" />
<xi:include href="appendix/faq.xml" />
<xi:include href="appendix/glossary.xml" />
</part>
</book>

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

@@ -0,0 +1,38 @@
<?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>
<section id="project">
<title>Project metadata</title>
<itemizedlist spacing="compact">
<listitem>
<para>Version control - <ulink
url="http://git.synyx.org/hades.git">git://github.com/SpringSource/spring-data-jpa.git</ulink></para>
</listitem>
<listitem>
<para>Bugtracker - <ulink
url="http://hades.synyx.org">https://jira.springsource.org/browse/DATAJPA</ulink></para>
</listitem>
<listitem>
<para>Release repository - <ulink
url="http://repo2.maven.org/maven2/org/synyx/hades"><ulink
url="http://maven.springframework.org/release">http://maven.springframework.org/release</ulink></ulink></para>
</listitem>
<listitem>
<para>Milestone repsitory - <ulink
url="http://maven.springframework.org/milestone">http://maven.springframework.org/milestone</ulink></para>
</listitem>
<listitem>
<para>Snapshot repsitory - <ulink
url="http://maven.springframework.org/snapshot">http://maven.springframework.org/snapshot</ulink></para>
</listitem>
</itemizedlist>
</section>
</preface>

View File

@@ -0,0 +1,673 @@
<?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="repositories">
<title>Repositories</title>
<section id="introduction">
<title>Introduction</title>
<para>Implementing a data access layer of an application has been
cumbersome for quite a while. Too much boilerplate code had to be written.
Domain classes were anemic and haven't been designed in a real object
oriented or domain driven manner.</para>
<para>Using both of these technologies makes developers life a lot easier
regarding rich domain model's persistence. Nevertheless the amount of
boilerplate code to implement repositories especially is still quite high.
So the goal of the repository abstraction of Spring Data is to reduce the
effort to implement data access layers for various persistence stores
significantly</para>
<para>The following chapters will introduce the core concepts and
interfaces of Spring Data repositories.</para>
</section>
<section id="core-concepts">
<title>Core concepts</title>
<para>The central interface in Spring Data repository abstraction is
<interfacename>Repository</interfacename> (probably not that much of a
surprise). It is typeable to the domain class to manage as well as the id
type of the domain class and provides some sophisticated functionality
around CRUD for the entity managed.</para>
<example id="repository">
<title>Repository interface</title>
<programlistingco>
<areaspec>
<area coords="3" id="repository.save" />
<area coords="5" id="repository.find-by-id" />
<area coords="7" id="repository.find-all" />
<area coords="9" id="repository.find-all-pageable" />
<area coords="11" id="repository.count" />
<area coords="13" id="repository.delete" />
<area coords="15" id="repository.exists" />
</areaspec>
<programlisting language="java">public interface Repository&lt;T, ID extends Serializable&gt; {
T save(T entity);
T findById(ID primaryKey);
List&lt;T&gt; findAll();
Page&lt;T&gt; findAll(Pageable pageable);
Long count();
void delete(T entity);
boolean exists(ID primaryKey);
// … more functionality omitted.
}</programlisting>
<calloutlist>
<callout arearefs="repository.save">
<para>Saves the given entity.</para>
</callout>
<callout arch="" arearefs="repository.find-by-id">
<para>Returns the entity identified by the given id.</para>
</callout>
<callout arearefs="repository.find-all">
<para>Returns all entities.</para>
</callout>
<callout arch="" arearefs="repository.find-all-pageable">
<para>Returns a page of entities.</para>
</callout>
<callout arearefs="repository.count">
<para>Returns the number of entities.</para>
</callout>
<callout arearefs="repository.delete">
<para>Deletes the given entity.</para>
</callout>
<callout arearefs="repository.exists">
<para>Returns whether an entity with the given id exists.</para>
</callout>
</calloutlist>
</programlistingco>
</example>
<para>Usually we will have persistence technology specific sub-interfaces
to include additional technology specific methods. We will now ship
implementations for a variety of Spring Data modules that implement that
interface.</para>
</section>
<section id="query-methods">
<title>Query methods</title>
<para>Next to standard CRUD functionality repositories are usually query
the underlying datastore. With Spring Data declaring those queries becomes
a four-step process (we use the JPA based module as example but that works
the same way for other stores):</para>
<orderedlist>
<listitem>
<para>Declare an interface extending the technology specific
Repository sub-interface and type it to the domain class it shall
handle.</para>
<programlisting language="java">public interface PersonRepository extends JpaRepository&lt;User, Long&gt; { … }</programlisting>
</listitem>
<listitem>
<para>Declare query methods on the interface.</para>
<programlisting language="java">List&lt;Person&gt; findByLastname(String lastname);</programlisting>
</listitem>
<listitem>
<para>Setup Spring to create proxy instances for those
interfaces.</para>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/data/jpa
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"&gt;
&lt;repositories base-package="com.acme.repositories" /&gt;
&lt;/beans&gt;</programlisting>
</listitem>
<listitem>
<para>Get the repository instance injected and use it.</para>
<programlisting language="java">public class SomeClient {
@Autowired private PersonRepoyitory repository;
public void doSomething() {
List&lt;Person&gt; persons = repository.findByLastname("Matthews");
}</programlisting>
</listitem>
</orderedlist>
<para>At this stage we barely scratched the surface of what's possible
with the repositories but the general approach should be clear. Let's go
through each of these steps and and figure out details and various options
that you have at each stage.</para>
<section>
<title>Defining repository interfaces</title>
<para>As a very first step you define a domain class specific repository
interface to start with. It's got to be typed to the domain class and an
ID type so that you get CRUD methods of the
<interfacename>Repository</interfacename> interface tailored to
it.</para>
</section>
<section>
<title>Defining query methods</title>
<section>
<title>Query lookup strategies</title>
<para>The next thing we have to discuss is the definition of query
methods. There's roughly two main ways how the repository proxy is
generally able to come up with the store specific query from the
method name. The first option is to derive the quer from the method
name directly, the second is using some kind of additionally created
query. What detailed options are available pretty much depends on the
actual store. However there's got to be some algorithm the decision
which actual query to is made.</para>
<para>There's three strategies for the repository infrastructure to
resolve the query. The strategy to be used can be configured at the
namespace through the <code>query-lookup-strategy</code> attribute.
However might be the case that some of the strategies are not
supported for the specific datastore. Here are your options:</para>
<simplesect>
<title>CREATE</title>
<para>This strategy will try to construct a store specific query
from the query method's name. The general approach is to remove a
given set of well-known prefixes from the method name and parse the
rest of the method. Read more about query construction in <xref
linkend="query-methods.query-creation" />.</para>
</simplesect>
<simplesect>
<title>USE_DECLARED_QUERY</title>
<para>This strategy tries to find a declared query which will be
used for execution first. The query could be defined by an
annotation somwhere or declared by other means. Please consult the
documentation of the specific store to find out what options are
available for that store. If the repository infrastructure does not
find a declared query for the method at bootstrap time it will
fail.</para>
</simplesect>
<simplesect>
<title>CREATE_IF_NOT_FOUND (default)</title>
<para>This strategy is actually a combination of the both mentioned
above. It will try to lookup a declared query first but create a
custom method name based query if no declared query was found. This
is default lookup strategy and thus will be used if you don't
configure anything explicitly. It allows quick query definition by
method names but also custom tuning of these queries by introducing
declared queries for those who need explicit tuning.</para>
</simplesect>
</section>
<section id="query-methods.query-creation">
<title>Query creation</title>
<para>The query builder mechanism built into Spring Data repository
infrastructue is useful to build constraining queries over entities of
the repository. We will strip the prefixes <code>findBy</code>,
<code>find</code>, <code>readBy</code>, <code>read</code>,
<code>getBy</code> as well as <code>get</code> from the method and
start parsing the rest of it. At a very basic level you can define
conditions on entity properties and concatenate them with
<code>AND</code> and <code>OR</code>.</para>
<example>
<title>Query creation from method names</title>
<para><programlisting language="java">public interface PersonRepository extends JpaRepository&lt;User, Long&gt; {
List&lt;Person&gt; findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
}</programlisting></para>
</example>
<para>The actual result of parsing that method will of course depend
on the persistence store we create the query for. However there are
some general things to notice. The expression are usually property
traversals combined with operators that can be concatenated. As you
can see in the example you can combine property expressions with And
and Or. Beyond that you will get support for various operators like
Between, LessThan, GreaterThan, Like for the property expressions. As
the operators supported can vary from datastore to datastore please
consult the according part of the reference documentation.</para>
<section>
<title>Property expressions</title>
<para>Property expressions can just refer to a direct property of
the managed entity (as you just saw in the example above. On query
creation time we already make sure that the parsed property is at a
property of the managed domain class. However you can also traverse
nested properties to define constraints on. Assume
<classname>Person</classname>s have <classname>Address</classname>es
with <classname>ZipCode</classname>s. In that case a method name
of</para>
<programlisting language="java">List&lt;Person&gt; findByAddressZipCode(ZipCode zipCode);</programlisting>
<para>will create the property traversal
<code>x.address.zipCode</code>. The resolution algorithm starts with
interpreting the entire part (<literal>AddressZipCode</literal>) as
property and checks the domain class for a property with that name
(uncapitalized). If it succeeds it just uses that. If not it starts
splitting up the source at the camel case parts from the right side
into a head and a tail and tries to find the according property,
e.g. <literal>AddressZip</literal> and <literal>Code</literal>. If
we find a property with that head we take the tail and continue
building the tree down from there. As in our case the first split
does not match we move the split point to the left
(<literal>Address</literal>, <literal>ZipCode</literal>).</para>
<para>Now although this should work for most cases, there might be
cases where the algorithm could select the wrong property. Suppose
our <classname>Person</classname> class has a
<code>addressZip</code> property as well. Then our algorithm would
match in the first split round already and essentially choose the
wrong property and finally fail (as the type of
<classname>addressZip</classname> probably has no code property). To
resolve this ambiguity you can use <literal>_</literal> inside your
method name to manually define traversal points. So our method name
would end up like so:</para>
<programlisting language="java">List&lt;Person&gt; findByAddress_ZipCode(ZipCode zipCode);
</programlisting>
</section>
</section>
<section id="special-parameters">
<title>Special parameter handling</title>
<para>To hand parameters to your query you simply define method
parameters as already seen in in examples above. Besides that we will
recognizes certain specific types to apply pagination and sorting to
your queries dynamically.</para>
<example>
<title>Using Pageable and Sort in query methods</title>
<programlisting>Page&lt;User&gt; findByLastname(String lastname, Pageable pageable);
List&lt;User&gt; findByLastname(String lastname, Sort sort);
List&lt;User&gt; findByLastname(String lastname, Pageable pageable);</programlisting>
</example>
<para>The first method allows you to pass a <code>Pageable</code>
instance to the query method to dynamically add paging to your
statically defined query. <code>Sorting</code> options are handed via
the <interfacename>Pageable</interfacename> instance, too. If you only
need sorting, simply add a <code>Sort</code> parameter to your method.
As you also can see, simply returning a
<interfacename>List</interfacename> is possible as well. We will then
not retrieve the additional metadata required to build the actual
<interfacename>Page</interfacename> instance but rather simply
restrict the query to lookup only the given range of entities.</para>
<note>
<para>To find out how many pages you get for a query entirely we
have to trigger an additional count query. This will be derived from
the query you actually trigger by default.</para>
</note>
</section>
</section>
<section>
<title>Creating repository instances</title>
<para>So now the question is how to create instances and bean
definitions for the repository interfaces defined.</para>
<section>
<title>Spring</title>
<para>The easiest way to do so is by using the Spring namespace that
is shipped with each Spring Data module that supports the repository
mechanism. Each of those includes a repositories element that allows
you to simply define a base packge Spring shall scan for you.</para>
<programlisting language="java">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/data/jpa
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"&gt;
&lt;repositories base-package="com.acme.repositories" /&gt;
&lt;/beans:beans&gt;</programlisting>
<para>In this case we instruct Spring to scan
<package>com.acme.repositories</package> and all it's sub packages for
interfaces extending the appropriate
<interfacename>Repository</interfacename> sub-interface (in this case
<interfacename>JpaRepository</interfacename>). For each interface
found it will register the presistence technology specific
<interfacename>FactoryBean</interfacename> to create the according
proxies that handle invocations of the query methods. Each of these
beans will be registered under a bean name that is derived from the
interface name, so an interface of
<interfacename>UserRepository</interfacename> would be registered
under <code>userRepository</code>. The <code>base-package</code>
attribute allows to use wildcards, so that you can have a pattern of
packages parsed. </para>
<simplesect>
<title>Using filters</title>
<para>By default we will pick up every interface extending the
persistence technology specific
<interfacename>Repository</interfacename> sub-interface located
underneath the configured base package and create a bean instance
for it. However, you might want to gain finer grained control over
which interfaces bean instances get created for. To do this we
support the use of <code>&lt;include-filter /&gt;</code> and
<code>&lt;exclude-filter /&gt;</code> elements inside
<code>&lt;repositories /&gt;</code>. The semantics are exactly
equivalent to the elements in Spring's context namespace. For
details see <ulink
url="http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-scanning-filters"
vendor="">Spring reference documentation</ulink> on these
elements.</para>
<para>E.g. to exclude certain interfaces from instantiation as
repository, you could use the following configuration:</para>
<example>
<title>Using exclude-filter element</title>
<programlisting language="xml">&lt;repositories base-package="com.acme.repositories"&gt;
&lt;context:exclude-filter type="regex" expression=".*SomeRepository" /&gt;
&lt;/repositories&gt;
</programlisting>
<para>This would exclude all interface ending on
<interfacename>SomeRepository</interfacename> from being
instantiated.</para>
</example>
</simplesect>
<simplesect>
<title>Manual configuration</title>
<para>If you'd rather like to manually define which repository
instances to create you can do this with nested <code>&lt;repository
/&gt;</code> elements.</para>
<programlisting language="java">&lt;repositories base-package="com.acme.repositories"&gt;
&lt;repository id="userRepository" /&gt;
&lt;/repositories&gt;
</programlisting>
</simplesect>
</section>
<section>
<title>Standalone usage</title>
<para>You can also use the repository infrastructure outside of a
Spring container usage. You will still need to have some of the Spring
libraries on your classpath but you can generally setup repositories
programatically as well. The Spring Data modules providing repository
support ship a persistence technology specific RepositoryFactory that
can be used as follows:</para>
<example>
<title>Standalone usage of repository factory</title>
<programlisting>RepositoryFactorySupport factory = … // Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class</programlisting>
</example>
</section>
</section>
</section>
<section id="custom-implementations">
<title>Custom implementations</title>
<section id="single-repository-behaviour">
<title>Adding behaviour to single repositories</title>
<para>Often it is necessary to provide a custom implementation for a few
repository methods. Spring Data repositories easily allow provide custom
repository code and integrate it with generic CRUD abstraction and query
method functionality. To enrich a repository with custom functionality
you have to define an interface and an implementation for that
functionality first and let the repository interface you provided so far
extend that custom interface.</para>
<example>
<title>Interface for custom repository functionality</title>
<programlisting language="java">interface UserRepositoryCustom {
public void someCustomMethod(User user);
}</programlisting>
</example>
<example>
<title>Implementation of custom repository functionality</title>
<para><programlisting language="java">class UserRepositoryImpl implements UserRepositoryCustom {
public void someCustomMethod(User user) {
// Your custom implementation
}
}</programlisting>Note that the implementation itself does not depend on
Spring Data and can be a regular Spring bean. So you can either use
standard dependency injection behaviour to inject references to other
beans, take part in aspects and so on.</para>
</example>
<example>
<title>Changes to the your basic repository interface</title>
<para><programlisting language="java">public interface UserRepository extends JpaRepository&lt;User, Long&gt;, UserRepositoryCustom {
// Declare query methods here
}</programlisting>Let your standard repository interface extend the custom
one. This makes CRUD and custom functionality available to
clients.</para>
</example>
<simplesect>
<title>Configuration</title>
<para>If you use namespace configuration the repository infrastructure
tries to autodetect custom implementations by looking up classes in
the package we found a repository using the naming conventions
appending the namespace element's attribute
<code>repository-impl-postfix</code> to the classname. This suffix
defaults to <code>Impl</code>.</para>
<example>
<title>Configuration example</title>
<para><programlisting language="xml">&lt;repositories base-package="com.acme.repository"&gt;
&lt;repository id="userRepository" /&gt;
&lt;/repositories&gt;
&lt;repositories base-package="com.acme.repository" repository-impl-postfix="FooBar"&gt;
&lt;repository id="userRepository" /&gt;
&lt;/repositories&gt;</programlisting></para>
</example>
<para>The first configuration example will try to lookup a class
<classname>com.acme.repository.UserRepositoryImpl</classname> to act
as custom repository implementation, where the second example will try
to lookup
<classname>com.acme.repository.UserRepositoryFooBar</classname>.</para>
</simplesect>
<simplesect>
<title>Manual wiring</title>
<para>The approach above works perfectly well if your custom
implementation uses annotation based configuration and autowring
entirely as will be trated as any other Spring bean. If your customly
implemented bean needs some special wiring you simply declare the bean
and name it after the conventions just descibed. We will then pick up
the custom bean by name rather than creating an own instance.</para>
<example>
<title>Manual wiring of custom implementations (I)</title>
<programlisting language="xml">&lt;repositories base-package="com.acme.repository"&gt;
&lt;repository id="userRepository" /&gt;
&lt;/repositories&gt;
&lt;beans:bean id="userRepositoryImpl" class="…"&gt;
&lt;!-- further configuration --&gt;
&lt;/beans:bean&gt;</programlisting>
<para>This also works if you use automatic repository lookup without
defining single <code>&lt;repository /&gt;</code> elements.</para>
</example>
<para>In case you are not in control of the implementation bean name
(e.g. if you wrap a generic repository facade around an existing
repository implementation) you can explicitly tell the
<code>&lt;repository /&gt;</code> element which bean to use as custom
implementation by using the <code>repository-impl-ref</code>
attribute.</para>
<example>
<title>Manual wiring of custom implementations (II)</title>
<para><programlisting language="xml">&lt;repositories base-package="com.acme.repository"&gt;
&lt;repository id="userRepository" repository-impl-ref="customRepositoryImplementation" /&gt;
&lt;/repositories&gt;
&lt;bean id="customRepositoryImplementation" class="…"&gt;
&lt;!-- further configuration --&gt;
&lt;/bean&gt;</programlisting></para>
</example>
</simplesect>
</section>
<section id="custom-behaviour-for-all-repositories">
<title>Adding custom behaviour to all repositories</title>
<para>In other cases you might want to add a single method to all of
your repository interfaces. So the approach just shown is not feasible.
The first step to achieve this is adding and intermediate interface to
declare the shared behaviour</para>
<example>
<title>An interface declaring custom shared behaviour</title>
<para><programlisting language="java">public interface MyRepository&lt;T, ID extends Serializable&gt;
extends JpaRepository&lt;T, ID&gt; {
void sharedCustomMethod(ID id);
}</programlisting></para>
</example>
<para>Now your individual repository interfaces will extend this
intermediate interface to include the functionality declared. The second
step is to create an implementation of this interface that extends the
persistence technology specific repository base class which will act as
custom base class for the repository proxies then.</para>
<note>
<para>If you're using automatic repository interface detection using
the Spring namespace using the interface just as is will cause Spring
trying to create an instance of
<interfacename>MyRepository</interfacename>. This is of course not
desired as it just acts as indermediate between
<interfacename>Repository</interfacename> and the actual repository
interfaces you want to define for each entity. To exclude an interface
extending <interfacename>Repository</interfacename> from being
instantiated as repository instance annotate it with
<interfacename>@NoRepositoryBean</interfacename>.</para>
</note>
<example>
<title>Custom repository base class</title>
<programlisting language="java">public class MyRepositoryImpl&lt;T, ID extends Serializable&gt;
extends SimpleJpaRepository&lt;T, ID&gt; implements MyRepository&lt;T, ID&gt; {
public void sharedCustomMethod(ID id) {
// implementation goes here
}
}</programlisting>
</example>
<para>The last step to get this implementation used as base class for
Spring Data repositores is replacing the standard
<classname>RepositoryFactoryBean</classname> with a custom one using a
custom <classname>RepositoryFactory</classname> that in turn creates
instances of your <classname>MyRepositoryImpl</classname> class.</para>
<example>
<title>Custom repository factory bean</title>
<programlisting language="java">public class MyRepositoryFactoryBean&lt;T extends JpaRepository&lt;?, ?&gt;
extends JpaRepositoryFactoryBean&lt;T&gt; {
protected RepositoryFactorySupport getRepositoryFactory(…) {
return new MyRepositoryFactory(…);
}
private static class MyRepositoryFactory extends JpaRepositoryFactory{
public MyRepositoryImpl getTargetRepository(…) {
return new MyRepositoryImpl(…);
}
public Class&lt;? extends RepositorySupport&gt; getRepositoryClass() {
return MyRepositoryImpl.class;
}
}
}</programlisting>
</example>
<para>Finally you can either declare beans of the custom factory
directly or use the <code>factory-class</code> attribute of the Spring
namespace to tell the repository infrastructure to use your custom
factory implementation.</para>
<example>
<title>Using the custom factory with the namespace</title>
<programlisting language="xml">&lt;repositories base-package="com.acme.repository"
factory-class="com.acme.MyRepositoryFactoryBean" /&gt;</programlisting>
</example>
</section>
</section>
</chapter>

View File

@@ -0,0 +1,680 @@
<?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="jpa.repositories">
<title>JPA Repositories</title>
<abstract>
<para>This chapter includes details of the JPA repository
implementation.</para>
</abstract>
<section id="jpa.query-methods">
<title>Query methods</title>
<section id="jpa.sample-app.finders.strategies">
<title>Query lookup strategies</title>
<para>The JPA module supports defining a query manually as String or
have it being derived from the method name.</para>
<simplesect>
<title>Declared queries</title>
<para>Although getting a query derived from the method name is quite
convenient one might face the situation in which either the method
name parser does not support the keyword one wants to use or the
method name would get unnecessarily ugly. So you can either use JPA
named queries through a naming convention (see <xref
linkend="jpa.query-methods.named-queries" /> for more information) or
rather annotate your query method with
<interfacename>@Query</interfacename> (see as for details).</para>
</simplesect>
<simplesect>
<title>Strategies</title>
<para>This strategy tries to find a declared query that can either be
defined using JPA <code>@NamedQuery</code> means or Hades
<code>@Query</code> annotation (see <xref
linkend="jpa.query-methods.named-queries" /> and <xref
linkend="jpa.query-methods.at-query" /> for details). If no declared
query is found execution of the query will fail.</para>
</simplesect>
<simplesect>
<title>CREATE_IF_NOT_FOUND (default)</title>
<para>This strategy is actually a combination of the both mentioned
above. It will try to lookup a declared query first but create a
custom method name based query if no named query was found. This is
default lookup strategy and thus will be used if you don't configure
anything explicitly. It allows quick query definition by method names
but also custom tuning of these queries by introducing declared
queries for those who need explicit tuning.</para>
</simplesect>
</section>
<section id="jpa.query-methods.query-creation">
<title>Query creation</title>
<para>Generally the query creation mechanism for JPA works as described
in <xref linkend="repositories.query-methods" />. Here's a short example
of what a JPA query method translates into:<example>
<title>Query creation from method names</title>
<para><programlisting language="java">public interface UserRepository extends Repository&lt;User, Long&gt; {
List&lt;User&gt; findByEmailAddressAndLastname(String emailAddress, String lastname);
}</programlisting>We will create a query using the JPA criteria API from this
but essentially this translates into the following query:</para>
<programlisting>select u from User u where u.emailAddress = ?1 and u.lastname = ?2</programlisting>
<para>Spring Data JPA will do a property check and traverse nested
properties like described in <xref
linkend="repositories.query-methods.property-expressions" />. Here's
an overview of the keywords supported for JPA and what a method
containing that keyword essentially translates to.</para>
</example></para>
<para><table>
<title>Supported keywords inside method names</title>
<tgroup cols="3">
<colspec colwidth="1*" />
<colspec colwidth="2*" />
<colspec colwidth="3*" />
<thead>
<row>
<entry>Keyword</entry>
<entry>Sample</entry>
<entry>JPQL snippet</entry>
</row>
</thead>
<tbody>
<row>
<entry><code>And</code></entry>
<entry><code>findByLastnameAndFirstname</code></entry>
<entry><code>… where x.lastname = ?1 and x.firstname =
?2</code></entry>
</row>
<row>
<entry><code>Or</code></entry>
<entry><code>findByLastnameOrFirstname</code></entry>
<entry><code>… where x.lastname = ?1 or x.firstname =
?2</code></entry>
</row>
<row>
<entry><code>Between</code></entry>
<entry><code>findByStartDateBetween</code></entry>
<entry><code>… where x.startDate between 1? and
?2</code></entry>
</row>
<row>
<entry><code>LessThan</code></entry>
<entry><code>findByAgeLessThan</code></entry>
<entry><code>… where x.age &lt; ?1</code></entry>
</row>
<row>
<entry><code>GreaterThan</code></entry>
<entry><code>findByAgeGreaterThan</code></entry>
<entry><code>… where x.age &gt; ?1</code></entry>
</row>
<row>
<entry><code>IsNull</code></entry>
<entry><code>findByAgeIsNull</code></entry>
<entry><code>… where x.age is null</code></entry>
</row>
<row>
<entry><code>IsNotNull,NotNull</code></entry>
<entry><code>findByAge(Is)NotNull</code></entry>
<entry><code>… where x.age not null</code></entry>
</row>
<row>
<entry><code>Like</code></entry>
<entry><code>findByFirstnameLike</code></entry>
<entry><code>… where x.firstname like ?1</code></entry>
</row>
<row>
<entry><code>NotLike</code></entry>
<entry><code>findByFirstnameNotLike</code></entry>
<entry><code>… where x.firstname not like ?1</code></entry>
</row>
<row>
<entry><code>OrderBy</code></entry>
<entry><code>findByAgeOrderByLastnameDesc</code></entry>
<entry><code>… where x.age &gt; ?1 order by x.lastname
desc</code></entry>
</row>
<row>
<entry><code>Not</code></entry>
<entry><code>findByLastnameNot</code></entry>
<entry><code>… where x.lastname &lt;&gt; ?1</code></entry>
</row>
</tbody>
</tgroup>
</table></para>
</section>
<section id="jpa.query-methods.named-queries">
<title>Using JPA NamedQueries</title>
<note>
<para>The examples use simple <code>&lt;named-query /&gt;</code>
element and <code>@NamedQuery</code> annotation. The queries for these
configuration elements have to be defined in JPA query language. Of
course you can use <code>&lt;named-native-query /&gt;</code> or
<code>@NamedNativeQuery</code>, too. These elements allow you to
define the query in native SQL by losing the database platform
independence.</para>
</note>
<simplesect>
<title>XML named query definition</title>
<para>To use XML configuration simply add the necessary
<code>&lt;named-query /&gt;</code> element to the
<filename>orm.xml</filename> JPA configuration file located in
<filename>META-INF</filename> folder of your classpath. Automatic
invocation of named queries is enabled by using some defined naming
convention. For more details see below.</para>
<example>
<title>XML named query configuration</title>
<programlisting language="xml">&lt;named-query name="User.findByLastname"&gt;
&lt;query&gt;select u from User u where u.lastname = ?1&lt;/query&gt;
&lt;/named-query&gt;</programlisting>
</example>
<para>As you can see the query has a special name which will be used
to resolve it at runtime.</para>
</simplesect>
<simplesect>
<title>Annotation configuration</title>
<para>Annotation configuration has the advantage not to need another
config file to be edited, probably lowering maintenance cost. You pay
for that benefit by the need to recompile your domain class for every
new query declaration.</para>
<example>
<title>Annotation based named query configuration</title>
<programlisting language="java">@Entity
@NamedQuery(name = "User.findByEmailAddress",
query = "select u from User u where u.emailAddress = ?1")
public class User {
}</programlisting>
</example>
</simplesect>
<simplesect>
<title>Declaring interfaces</title>
<para>To allow execution of this named query all you need to do is to
specify the <interfacename>UserRepository</interfacename> as
follows:</para>
<example>
<title>Query method declaration in UserRepository</title>
<programlisting language="java">public interface UserRepository extends JpaRepository&lt;User, Long&gt; {
List&lt;User&gt; findByLastname(String lastname);
User findByEmailAddress(String emailAddress);
}</programlisting>
</example>
<para>Declaring this method we will try to resolve a call to this
method to a named query starting with the simple name of the
configured domain class followed by the method name separated by a
dot. So the example here would use the named queries defined above
instead of trying to create a query from the method name.</para>
</simplesect>
</section>
<section id="jpa.query-methods.at-query">
<title>Using @Query</title>
<para>Using named queries to declare queries for entities is a valid
approach and works fine for a small number amount of queries. As the
queries themselves are tied to a Java method to execute them you
actually can bind them to the query executing methods using Spring Data
JPA <code>@Query</code> annotation rather than annotating them to the
domain class. This will free the domain class from persistence specific
information and colocate the query to the repository interface.</para>
<para>Querys annotated to the query method will trump queries defined
using <code>@NamedQuery</code> or named queries declared in in
<filename>orm.xml</filename>.</para>
<example>
<title>Declare query at the query method using @Query</title>
<programlisting language="java">public interface UserRepository extends JpaRepository&lt;User, Long&gt; {
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}</programlisting>
</example>
</section>
<section id="jpa.named-parameters">
<title>Using named parameters</title>
<para>By default Sprign Data JPA will use position based parameter
binding as described in all the samples above. This makes query methods
a little error prone to refactorings regarding the parameter position.
To solve this issue you can use <code>@Param</code> annotation to give a
method parameter a concrete name and bind the name in the query:</para>
<example>
<title>Using named parameters</title>
<programlisting language="java">public interface UserRepository extends JpaRepository&lt;User, Long&gt; {
@Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findByLastnameOrFirstname(@Param("lastname") String lastname,
@Param("firstname") String firstname);
}</programlisting>
<para>Note that the method parameters are switched according to the
occurrence in the query defined.</para>
</example>
</section>
<section id="jpa.modifying-queries">
<title>Modifying queries</title>
<para>All the sections before described how to declare queries to access
a given entity or collection of entitites. Of course you can add custom
modifying behaviour by using facilities described in <xref
linkend="custom-implementations" />. As this approach is feasible for
comprehensive custom functionality, you can achieve the execution of
modifying queries that actually only need parameter binding by
annotating the query method with <code>@Modifying</code>:</para>
<example>
<title>Declaring manipulating queries</title>
<programlisting language="java">@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);</programlisting>
</example>
<para>This will trigger the query annotated to the method as updating
query instead of a selecting one. As the
<interfacename>EntityManager</interfacename> might contain outdated
entities after the execution of the modifying query, we automatically
clear it (see JavaDoc of
<interfacename>EntityManager</interfacename>.<methodname>clear()</methodname>
for details). This will effectively drop all non-flushed changes still
pending in the <interfacename>EntityManager</interfacename>. If you
don't wish the <interfacename>EntityManager</interfacename> to be
cleared automatically you can set
<interfacename>@Modifying</interfacename> annotation's
<code>clearAutomatically</code> attribute to
<literal>false</literal>;</para>
</section>
</section>
<section id="specifications">
<title>Specifications</title>
<para>JPA 2 introduces a criteria API that can be used to build queries
programatically. Writing a criteria you actually define the where-clause
of a query for a query of the handled domain class. Taking another step
back these criterias can be regarded as predicate over the entity that is
verbalized by the JPA criteria API constraints.</para>
<para>Spring Data JPA now takes the concept of a specification from Eric
Evans' book Domain Driven Design, that carries the same semantics and
provides an API to define such
<interfacename>Specification</interfacename>s using the JPA criteria API.
Thus you find methods like this in
<interfacename>JpaRepository</interfacename>:</para>
<programlisting language="java">List&lt;T&gt; readAll(Specification&lt;T&gt; spec);</programlisting>
<para>The <interfacename>Specification</interfacename> interface now looks
as follows:</para>
<programlisting language="java">public interface Specification&lt;T&gt; {
Predicate toPredicate(Root&lt;T&gt; root, CriteriaQuery&lt;?&gt; query,
CriteriaBuilder builder);
}</programlisting>
<para>Okay, so what is the typical use case?
<interfacename>Specification</interfacename>s can easily be used to build
an extensible set of predicates on top of an entity that then can be
combined and used with <interfacename>JpaRepository</interfacename>
without the need of declaring a query (method) for every needed
combination of those. Here's an example:</para>
<example>
<title>Specifications for a Customer</title>
<programlisting language="java">public class CustomerSpecs {
public static Specification&lt;Customer&gt; isLongTermCustomer() {
return new Specification&lt;Customer&gt;() {
Predicate toPredicate(Root&lt;T&gt; root, CriteriaQuery&lt;?&gt; query,
CriteriaBuilder builder) {
LocalDate date = new LocalDate().minusYears(2);
return builder.lessThan(root.get(Customer_.createdAt), date);
}
};
}
public static Specification&lt;Customer&gt; hasSalesOfMoreThan(MontaryAmount value) {
return new Specification&lt;Customer&gt;() {
Predicate toPredicate(Root&lt;T&gt; root, CriteriaQuery&lt;?&gt; query,
CriteriaBuilder builder) {
// build query here
}
};
}
}</programlisting>
</example>
<para>Admittedly the amount of boilerplate leaves room for improvement
(that will hopefully be reduced by Java 8 closures) but the client side
becomes much nicer as you will see below. Besides that we have expressed
some criteria on a business requirement abstraction level and created
executable <interfacename>Specification</interfacename>s. So a client
might use a <interfacename>Specification</interfacename> as
follows:</para>
<example>
<title>Using a simple Specification</title>
<programlisting language="java">List&lt;Customer&gt; customers = customerRepository.findAll(isLongTermCustomer());</programlisting>
</example>
<para>Okay, why not simply creating a query for this kind of data access?
You're right. Using a single <interfacename>Specification</interfacename>
does not gain a lot of benefit over a plain query declaration. The power
of <interfacename>Specification</interfacename>s really shines when you
combine them to create new <interfacename>Specification</interfacename>
objects. You can achieve this through the
<classname>Specifications</classname> helper class we provide to build
expressions like this:</para>
<example>
<title>Combined Specifications</title>
<para><programlisting language="java">MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);
List&lt;Customer&gt; customers = customerRepository.readAll(
where(isLongTermCustomer()).or(hasSalesOfMoreThan(amount)));</programlisting>As
you can see, <classname>Specifications</classname> offers some gluecode
methods to chain and combine
<interfacename>Specification</interfacename>s. Thus extending your data
access layer is just a matter of creating new
<interfacename>Specification</interfacename> implementations and
combining them with ones already existing.</para>
</example>
</section>
<section id="transactions">
<title>Transactionality</title>
<para>CRUD methods on repository instances are transactional by default.
For reading operations the transaction configuration <code>readOnly</code>
flag is set to true, all others are configured with a plain
<classname>@Transactional</classname> so that default transaction
configuration applies. For details see JavaDoc of
<classname>Repository</classname>. If you need to tweak transaction
configuration for one of the methods declared in
<interfacename>Repository</interfacename> simply redeclare the method in
your repository interface as follows:</para>
<example>
<title>Custom transaction configuration for CRUD</title>
<programlisting language="java">public interface UserRepository extends JpaRepository&lt;User, Long&gt; {
@Override
@Transactional(timeout = 10)
public List&lt;User&gt; findAll();
// Further query method declarations
}</programlisting>
<para>This will cause the <methodname>findAll()</methodname> method to
be executed with a timeout of 10 seconds and without the
<code>readOnly</code> flag.</para>
</example>
<para>Another possibility to alter transactional behaviour is using a
facade or service implementation that typically covers more than one
repository. Its purpose is to define transactional boundaries for non-CRUD
operations:</para>
<example>
<title>Using a facade to define transactions for multiple repository
calls</title>
<programlisting language="java">@Service
class UserManagementImpl implements UserManagement {
private final UserRepository userRepository;
private final RoleRepository roleRepository;
@Autowired
public UserManagementImpl(UserRepository userRepository,
RoleRepository roleRepository) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
}
@Transactional
public void addRoleToAllUsers(String roleName) {
Role role = roleRepository.findByName(roleName);
for (User user : userRepository.readAll()) {
user.addRole(role);
userRepository.save(user);
}
}</programlisting>
<para>This will cause call to
<methodname>addRoleToAllUsers(…)</methodname> to run inside a
transaction (participating in an existing one or create a new one if
none already running). The transaction configuration at the repositories
will be neglected then as the outer transaction configuration determines
the actual one used. Note that you will have to activate
<code>&lt;tx:annotation-driven /&gt;</code> explicitly to get annotation
based configuration at facades working. The example above assumes you're
using component scanning.</para>
</example>
<section id="transactional-query-methods">
<title>Transactional query methods</title>
<para>To let your query methods be transactional simply use
<interfacename>@Transactional</interfacename> at the repository
interface you define.</para>
<example>
<title>Using @Transactional at query methods</title>
<programlisting language="java">@Transactional(readOnly = true)
public interface UserRepository extends JpaRepository&lt;User, Long&gt; {
List&lt;User&gt; findByLastname(String lastname);
@Modifying
@Transactional
@Query("delete from User u where u.active = false")
void deleteInactiveUsers();
}</programlisting>
<para>Typically you will use the <code>readOnly</code> flag set to
true as most of the query methods will be reading ones. In contrast to
that <methodname>deleteInactiveUsers()</methodname> makes use of the
<interfacename>@Modifying</interfacename> annotation and overrides the
transaction configuration. Thus the method will be executed with
<code>readOnly</code> flag set to false.</para>
</example>
<note>
<para>It's definitely reasonable to use transactions for read only
queries as we can mark them as such by setting the
<code>readOnly</code> flag. This will not act as check that you do not
trigger a manipulating query nevertheless (although some databases
reject e.g. <literal>INSERT</literal> or <literal>UPDATE</literal>
statements inside a transaction set to be read only) but gets
propagated as hint to the underlying JDBC driver to do performance
optimizations. Furthermore Spring will do some optimizations to the
underlying JPA provider. E.g. when used with Hibernate the flush mode
is set to <code>NEVER</code> when you configure a transaction as read
only which causes Hibernate to skip dirty checks that gets quite
noticeable on large object trees.</para>
</note>
</section>
</section>
<section id="jpa.auditing">
<title>Auditing</title>
<para>Most applications will require some auditability for entities
allowing to track creation date and user and modification date and user.
Spring Data JPA provides facilities to add this audition information to
entity transparently by AOP means. To take part in this functionality your
domain classes have to implement a more advanced interface:</para>
<example>
<title><interfacename>Auditable</interfacename> interface</title>
<programlisting language="java">public interface Auditable&lt;U, ID extends Serializable&gt;
extends Persistable&lt;ID&gt; {
U getCreatedBy();
void setCreatedBy(U createdBy);
DateTime getCreatedDate();
void setCreated(Date creationDate);
U getLastModifiedBy();
void setLastModifiedBy(U lastModifiedBy);
DateTime getLastModifiedDate();
void setLastModified(Date lastModifiedDate);
}</programlisting>
</example>
<para>As you can see the modifying entity itself only has to be an entity.
Mostly this will be some sort of User entity, so we chose U as parameter
type.</para>
<note>
<para>To minimize boilerplate code Spring Data JPA offers
<classname>AbstractPersistable</classname> and
<classname>AbstractAuditable</classname> base classes that implement and
preconfigure entities. Thus you can decide to only implement the
interface or enjoy more sophisticated support by extending the base
class.</para>
</note>
<simplesect>
<title>General auditing configuration</title>
<para>Spring Data JPA ships with an entity listener that can be used to
trigger capturing auditing information. So first you have to register
the <classname>AuditingEntityListener</classname> inside your
<filename>orm.xml</filename> to be used for all entities in your
persistence contexts:</para>
<example>
<title>Auditing configuration orm.xml</title>
<programlisting language="xml">&lt;persistence-unit-metadata&gt;
&lt;persistence-unit-defaults&gt;
&lt;entity-listeners&gt;
&lt;entity-listener class="….data.jpa.domain.support.AuditingEntityListener" /&gt;
&lt;/entity-listeners&gt;
&lt;/persistence-unit-defaults&gt;
&lt;/persistence-unit-metadata&gt;</programlisting>
</example>
<para>Now activating auditing functionlity is just a matter of adding
the Spring Data JPA <literal>auditing</literal> namespace element to
your configuration:</para>
<example>
<title>Activating auditing in the Spring configuration</title>
<programlisting language="xml">&lt;jpa:auditing auditor-aware-ref="yourAuditorAwareBean" /&gt;</programlisting>
</example>
<para>As you can see you have to provide a bean that implements the
<interfacename>AuditorAware</interfacename> interface which looks as
follows:</para>
<example>
<title><interfacename>AuditorAware</interfacename> interface</title>
<programlisting language="java">public interface AuditorAware&lt;T, ID extends Serializable&gt; {
T getCurrentAuditor();
}</programlisting>
</example>
<para>Usually you will have some kind of authentication component in
your application that tracks the user currently working with the system.
This component should be <interfacename>AuditorAware</interfacename> and
thus allow seemless tracking of the auditor.</para>
</simplesect>
</section>
</chapter>

View File

@@ -0,0 +1,35 @@
/*
code highlight CSS resemblign the Eclipse IDE default color schema
@author Costin Leau
*/
.hl-keyword {
color: #7F0055;
font-weight: bold;
}
.hl-comment {
color: #3F5F5F;
font-style: italic;
}
.hl-multiline-comment {
color: #3F5FBF;
font-style: italic;
}
.hl-tag {
color: #3F7F7F;
}
.hl-attribute {
color: #7F007F;
}
.hl-value {
color: #2A00FF;
}
.hl-string {
color: #2A00FF;
}

View File

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

View File

@@ -0,0 +1,99 @@
@IMPORT url("highlight.css");
html {
padding: 0pt;
margin: 0pt;
}
body {
margin-left: 10%;
margin-right: 10%;
font-family: Arial, Sans-serif;
}
div {
margin: 0pt;
}
p {
text-align: justify;
}
hr {
border: 1px solid gray;
background: gray;
}
h1,h2,h3,h4 {
color: #234623;
font-family: Arial, Sans-serif;
}
pre {
line-height: 1.0;
color: black;
}
pre.programlisting {
font-size: 10pt;
padding: 7pt 3pt;
border: 1pt solid black;
background: #eeeeee;
clear: both;
}
div.table {
margin: 1em;
padding: 0.5em;
text-align: center;
}
div.table table {
display: table;
width: 100%;
}
div.table td {
padding-left: 7px;
padding-right: 7px;
}
.sidebar {
float: right;
margin: 10px 0 10px 30px;
padding: 10px 20px 20px 20px;
width: 33%;
border: 1px solid black;
background-color: #F4F4F4;
font-size: 14px;
}
.mediaobject {
padding-top: 30px;
padding-bottom: 30px;
}
.legalnotice {
font-family: Verdana, Arial, helvetica, sans-serif;
font-size: 12px;
font-style: italic;
}
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;
}
span.productname {
font-size: 200%;
font-weight: bold;
font-family: Verdana, Arial, helvetica, sans-serif;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

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

View File

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

View File

@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xslthl="http://xslthl.sf.net"
exclude-result-prefixes="xslthl"
version='1.0'>
<xsl:param name="chunk.section.depth">'5'</xsl:param>
<xsl:param name="use.id.as.filename" select="1"/>
<!-- Extensions -->
<xsl:param name="use.extensions">1</xsl:param>
<xsl:param name="tablecolumns.extension">0</xsl:param>
<xsl:param name="callout.extensions">1</xsl:param>
<!-- Activate Graphics -->
<xsl:param name="admon.graphics" select="1"/>
<xsl:param name="admon.graphics.path">images/</xsl:param>
<xsl:param name="admon.graphics.extension">.gif</xsl:param>
<xsl:param name="callout.graphics" select="1" />
<xsl:param name="callout.defaultcolumn">120</xsl:param>
<xsl:param name="callout.graphics.path">images/callouts/</xsl:param>
<xsl:param name="callout.graphics.extension">.gif</xsl:param>
<xsl:param name="table.borders.with.css" select="1"/>
<xsl:param name="html.stylesheet">css/stylesheet.css</xsl:param>
<xsl:param name="html.stylesheet.type">text/css</xsl:param>
<xsl:param name="generate.toc">book toc,title</xsl:param>
<xsl:param name="admonition.title.properties">text-align: left</xsl:param>
<!-- Label Chapters and Sections (numbering) -->
<xsl:param name="chapter.autolabel" select="1"/>
<xsl:param name="section.autolabel" select="1"/>
<xsl:param name="section.autolabel.max.depth" select="3"/>
<xsl:param name="section.label.includes.component.label" select="1"/>
<xsl:param name="table.footnote.number.format" select="'1'"/>
<!-- Show only Sections up to level 3 in the TOCs -->
<xsl:param name="toc.section.depth">3</xsl:param>
<!-- Remove "Chapter" from the Chapter titles... -->
<xsl:param name="local.l10n.xml" select="document('')"/>
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
<l:l10n language="en">
<l:context name="title-numbered">
<l:template name="chapter" text="%n.&#160;%t"/>
<l:template name="section" text="%n&#160;%t"/>
</l:context>
</l:l10n>
</l:i18n>
<!-- Use code syntax highlighting -->
<xsl:param name="highlight.source" select="1"/>
<xsl:template match='xslthl:keyword'>
<span class="hl-keyword"><xsl:value-of select='.'/></span>
</xsl:template>
<xsl:template match='xslthl:comment'>
<span class="hl-comment"><xsl:value-of select='.'/></span>
</xsl:template>
<xsl:template match='xslthl:oneline-comment'>
<span class="hl-comment"><xsl:value-of select='.'/></span>
</xsl:template>
<xsl:template match='xslthl:multiline-comment'>
<span class="hl-multiline-comment"><xsl:value-of select='.'/></span>
</xsl:template>
<xsl:template match='xslthl:tag'>
<span class="hl-tag"><xsl:value-of select='.'/></span>
</xsl:template>
<xsl:template match='xslthl:attribute'>
<span class="hl-attribute"><xsl:value-of select='.'/></span>
</xsl:template>
<xsl:template match='xslthl:value'>
<span class="hl-value"><xsl:value-of select='.'/></span>
</xsl:template>
<xsl:template match='xslthl:string'>
<span class="hl-string"><xsl:value-of select='.'/></span>
</xsl:template>
<!-- Google Analytics -->
<xsl:template name="user.head.content">
<xsl:comment>Begin Google Analytics code</xsl:comment>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-2728886-3");
pageTracker._setDomainName("none");
pageTracker._setAllowLinker(true);
pageTracker._trackPageview();
</script>
<xsl:comment>End Google Analytics code</xsl:comment>
</xsl:template>
<!-- Loopfuse -->
<xsl:template name="user.footer.content">
<xsl:comment>Begin LoopFuse code</xsl:comment>
<script src="http://loopfuse.net/webrecorder/js/listen.js" type="text/javascript">
</script>
<script type="text/javascript">
_lf_cid = "LF_48be82fa";
_lf_remora();
</script>
<xsl:comment>End LoopFuse code</xsl:comment>
</xsl:template>
</xsl:stylesheet>

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0"
xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- ==================================================================== -->
<t:titlepage t:element="book" t:wrapper="div" class="titlepage">
<t:titlepage-content t:side="recto">
<productname/>
<title/>
<subtitle/>
<!-- <corpauthor/>
<authorgroup/>
<author/>
<mediaobject/> -->
<othercredit/>
<releaseinfo/>
<copyright/>
<legalnotice/>
<pubdate/>
<revision/>
<revhistory/>
<abstract/>
</t:titlepage-content>
<t:titlepage-content t:side="verso">
</t:titlepage-content>
<t:titlepage-separator>
<hr/>
</t:titlepage-separator>
<t:titlepage-before t:side="recto">
</t:titlepage-before>
<t:titlepage-before t:side="verso">
</t:titlepage-before>
</t:titlepage>
</t:templates>

View File

@@ -0,0 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This is the XSL HTML configuration file for the Spring Reference Documentation.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<xsl:import href="urn:docbkx:stylesheet"/>
<!--###################################################
HTML Settings
################################################### -->
<xsl:param name="chunk.section.depth">'5'</xsl:param>
<xsl:param name="use.id.as.filename">'1'</xsl:param>
<!-- 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.graphics">1</xsl:param>
<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 SpringSource 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.springsource.com/" title="SpringSource">
<img style="border:none;position:absolute;padding-top:5px;right:42px;" src="images/s2_box_logo.png"/>
</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 SpringSource' strapline (or somesuch) across the bottom of each page -->
<xsl:template name="footer.navigation">
<xsl:param name="prev" select="/foo"/>
<xsl:param name="next" select="/foo"/>
<xsl:param name="nav.context"/>
<xsl:variable name="home" select="/*[1]"/>
<xsl:variable name="up" select="parent::*"/>
<xsl:variable name="row1" select="count($prev) &gt; 0
or count($up) &gt; 0
or count($next) &gt; 0"/>
<xsl:variable name="row2" select="($prev and $navig.showtitles != 0)
or (generate-id($home) != generate-id(.)
or $nav.context = 'toc')
or ($chunk.tocs.and.lots != 0
and $nav.context != 'toc')
or ($next and $navig.showtitles != 0)"/>
<xsl:if test="$suppress.navigation = '0' and $suppress.footer.navigation = '0'">
<div class="navfooter">
<xsl:if test="$footer.rule != 0">
<hr/>
</xsl:if>
<xsl:if test="$row1 or $row2">
<table width="100%" summary="Navigation footer">
<xsl:if test="$row1">
<tr>
<td width="40%" align="left">
<xsl:if test="count($prev)>0">
<a accesskey="p">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$prev"/>
</xsl:call-template>
</xsl:attribute>
<xsl:call-template name="navig.content">
<xsl:with-param name="direction" select="'prev'"/>
</xsl:call-template>
</a>
</xsl:if>
<xsl:text>&#160;</xsl:text>
</td>
<td width="20%" align="center">
<xsl:choose>
<xsl:when test="$home != . or $nav.context = 'toc'">
<a accesskey="h">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$home"/>
</xsl:call-template>
</xsl:attribute>
<xsl:call-template name="navig.content">
<xsl:with-param name="direction" select="'home'"/>
</xsl:call-template>
</a>
<xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'">
<xsl:text>&#160;|&#160;</xsl:text>
</xsl:if>
</xsl:when>
<xsl:otherwise>&#160;</xsl:otherwise>
</xsl:choose>
<xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'">
<a accesskey="t">
<xsl:attribute name="href">
<xsl:apply-templates select="/*[1]" mode="recursive-chunk-filename">
<xsl:with-param name="recursive" select="true()"/>
</xsl:apply-templates>
<xsl:text>-toc</xsl:text>
<xsl:value-of select="$html.ext"/>
</xsl:attribute>
<xsl:call-template name="gentext">
<xsl:with-param name="key" select="'nav-toc'"/>
</xsl:call-template>
</a>
</xsl:if>
</td>
<td width="40%" align="right">
<xsl:text>&#160;</xsl:text>
<xsl:if test="count($next)>0">
<a accesskey="n">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$next"/>
</xsl:call-template>
</xsl:attribute>
<xsl:call-template name="navig.content">
<xsl:with-param name="direction" select="'next'"/>
</xsl:call-template>
</a>
</xsl:if>
</td>
</tr>
</xsl:if>
<xsl:if test="$row2">
<tr>
<td width="40%" align="left" valign="top">
<xsl:if test="$navig.showtitles != 0">
<xsl:apply-templates select="$prev" mode="object.title.markup"/>
</xsl:if>
<xsl:text>&#160;</xsl:text>
</td>
<td width="20%" align="center">
<span style="color:white;font-size:90%;">
<a href="http://www.springsource.com/"
title="SpringSource">Sponsored by SpringSource
</a>
</span>
</td>
<td width="40%" align="right" valign="top">
<xsl:text>&#160;</xsl:text>
<xsl:if test="$navig.showtitles != 0">
<xsl:apply-templates select="$next" mode="object.title.markup"/>
</xsl:if>
</td>
</tr>
</xsl:if>
</table>
</xsl:if>
</div>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

View File

@@ -0,0 +1,518 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xslthl="http://xslthl.sf.net"
exclude-result-prefixes="xslthl"
version='1.0'>
<!-- Use nice graphics for admonitions -->
<xsl:param name="admon.graphics">'1'</xsl:param>
<xsl:param name="admon.graphics.path">@file.prefix@@dbf.xsl@/images/</xsl:param>
<xsl:param name="draft.watermark.image" select="'@file.prefix@@dbf.xsl@/images/draft.png'"/>
<xsl:param name="paper.type" select="'@paper.type@'"/>
<xsl:param name="page.margin.top" select="'1cm'"/>
<xsl:param name="region.before.extent" select="'1cm'"/>
<xsl:param name="body.margin.top" select="'1.5cm'"/>
<xsl:param name="body.margin.bottom" select="'1.5cm'"/>
<xsl:param name="region.after.extent" select="'1cm'"/>
<xsl:param name="page.margin.bottom" select="'1cm'"/>
<xsl:param name="title.margin.left" select="'0cm'"/>
<!--###################################################
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>
<!--###################################################
Table of Contents
################################################### -->
<xsl:param name="generate.toc">
book toc,title
</xsl:param>
<!--###################################################
Custom Header
################################################### -->
<xsl:template name="header.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:choose>
<xsl:when test="//productname">
<xsl:value-of select="//productname"/><xsl:text> </xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>please define productname in your docbook file!</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$sequence='blank'">
<xsl:choose>
<xsl:when test="$position='center'">
<xsl:value-of select="$Version"/>
</xsl:when>
<xsl:otherwise>
<!-- nop -->
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$pageclass='titlepage'">
<!-- nop: other titlepage sequences have no header -->
</xsl:when>
<xsl:when test="$position='center'">
<xsl:value-of select="$Version"/>
</xsl:when>
<xsl:otherwise>
<!-- nop -->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--###################################################
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:choose>
<xsl:when test="//releaseinfo">
<xsl:value-of select="//releaseinfo"/>
</xsl:when>
<xsl:otherwise>
<!-- nop -->
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="Title">
<xsl:value-of select="//title"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$sequence='blank'">
<xsl:choose>
<xsl:when test="$double.sided != 0 and $position = 'left'">
<xsl:value-of select="$Version"/>
</xsl:when>
<xsl:when test="$double.sided = 0 and $position = 'center'">
<!-- nop -->
</xsl:when>
<xsl:otherwise>
<fo:page-number/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$pageclass='titlepage'">
<!-- nop: other titlepage sequences have no footer -->
</xsl:when>
<xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'">
<fo:page-number/>
</xsl:when>
<xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'">
<fo:page-number/>
</xsl:when>
<xsl:when test="$double.sided = 0 and $position='right'">
<fo:page-number/>
</xsl:when>
<xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'">
<xsl:value-of select="$Version"/>
</xsl:when>
<xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'">
<xsl:value-of select="$Version"/>
</xsl:when>
<xsl:when test="$double.sided = 0 and $position='left'">
<xsl:value-of select="$Version"/>
</xsl:when>
<xsl:when test="$position='center'">
<xsl:value-of select="$Title"/>
</xsl:when>
<xsl:otherwise>
<!-- nop -->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="processing-instruction('hard-pagebreak')">
<fo:block break-before='page'/>
</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>
<xsl:param name="fop.extensions">1</xsl:param>
<!--###################################################
Paper & Page Size
################################################### -->
<!-- Paper type, no headers on blank pages, no double sided printing -->
<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>
<!--###################################################
Fonts & Styles
################################################### -->
<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>
<!-- 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>
<xsl:attribute-set name="section.title.level4.properties">
<xsl:attribute name="space-before.optimum">0.3em</xsl:attribute>
<xsl:attribute name="space-before.minimum">0.3em</xsl:attribute>
<xsl:attribute name="space-before.maximum">0.3em</xsl:attribute>
<xsl:attribute name="font-size">
<xsl:value-of select="$body.font.master * 0.9"/>
<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>
<!-- Use code syntax highlighting -->
<xsl:param name="highlight.source" select="1"/>
<xsl:param name="highlight.default.language" select="xml" />
<xsl:template match='xslthl:keyword'>
<fo:inline font-weight="bold" color="#7F0055"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match='xslthl:comment'>
<fo:inline font-style="italic" color="#3F5F5F"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match='xslthl:oneline-comment'>
<fo:inline font-style="italic" color="#3F5F5F"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match='xslthl:multiline-comment'>
<fo:inline font-style="italic" color="#3F5FBF"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match='xslthl:tag'>
<fo:inline color="#3F7F7F"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match='xslthl:attribute'>
<fo:inline color="#7F007F"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match='xslthl:value'>
<fo:inline color="#2A00FF"><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match='xslthl:string'>
<fo:inline color="#2A00FF"><xsl:apply-templates/></fo:inline>
</xsl:template>
<!--###################################################
Tables
################################################### -->
<!-- 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" select="1"/>
<xsl:param name="section.autolabel" select="1"/>
<xsl:param name="section.autolabel.max.depth" select="1"/>
<xsl:param name="section.label.includes.component.label" select="1"/>
<xsl:param name="table.footnote.number.format" select="'1'"/>
<!--###################################################
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="space-after.minimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.maximum">0.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>
<xsl:attribute-set name="list.block.spacing">
<xsl:attribute name="space-before.optimum">0.1em</xsl:attribute>
<xsl:attribute name="space-before.minimum">0.1em</xsl:attribute>
<xsl:attribute name="space-before.maximum">0.1em</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="example.properties">
<xsl:attribute name="space-before.minimum">0.5em</xsl:attribute>
<xsl:attribute name="space-before.optimum">0.5em</xsl:attribute>
<xsl:attribute name="space-before.maximum">0.5em</xsl:attribute>
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
<xsl:attribute name="keep-together.within-column">always</xsl:attribute>
</xsl:attribute-set>
<!--###################################################
Title information for Figures, Examples etc.
################################################### -->
<xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing">
<xsl:attribute name="font-weight">normal</xsl:attribute>
<xsl:attribute name="font-style">italic</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-before.minimum">0.1em</xsl:attribute>
<xsl:attribute name="space-before.optimum">0.1em</xsl:attribute>
<xsl:attribute name="space-before.maximum">0.1em</xsl:attribute>
</xsl:attribute-set>
<!--###################################################
Callouts
################################################### -->
<!-- don't use images for callouts -->
<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>
<!--###################################################
Misc
################################################### -->
<!-- Placement of titles -->
<xsl:param name="formal.title.placement">
figure after
example after
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>
<xsl:param name="body.start.indent">0pt</xsl:param>
<!-- Show only Sections up to level 3 in the TOCs -->
<xsl:param name="toc.section.depth">3</xsl:param>
<!-- Remove "Chapter" from the Chapter titles... -->
<xsl:param name="local.l10n.xml" select="document('')"/>
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
<l:l10n language="en">
<l:context name="title-numbered">
<l:template name="chapter" text="%n.&#160;%t"/>
<l:template name="section" text="%n&#160;%t"/>
</l:context>
<l:context name="title">
<l:template name="example" text="Example&#160;%n&#160;%t"/>
</l:context>
</l:l10n>
</l:i18n>
<!--###################################################
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:template match="link">
<fo:basic-link internal-destination="{@linkend}"
xsl:use-attribute-sets="xref.properties"
text-decoration="underline"
color="blue">
<xsl:choose>
<xsl:when test="count(child::node())=0">
<xsl:value-of select="@linkend"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
</xsl:otherwise>
</xsl:choose>
</fo:basic-link>
</xsl:template>
</xsl:stylesheet>

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<!DOCTYPE t:templates [
<!ENTITY hsize0 "10pt">
<!ENTITY hsize1 "12pt">
<!ENTITY hsize2 "14.4pt">
<!ENTITY hsize3 "17.28pt">
<!ENTITY hsize4 "20.736pt">
<!ENTITY hsize5 "24.8832pt">
<!ENTITY hsize0space "7.5pt"> <!-- 0.75 * hsize0 -->
<!ENTITY hsize1space "9pt"> <!-- 0.75 * hsize1 -->
<!ENTITY hsize2space "10.8pt"> <!-- 0.75 * hsize2 -->
<!ENTITY hsize3space "12.96pt"> <!-- 0.75 * hsize3 -->
<!ENTITY hsize4space "15.552pt"> <!-- 0.75 * hsize4 -->
<!ENTITY hsize5space "18.6624pt"> <!-- 0.75 * hsize5 -->
]>
<t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0"
xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<t:titlepage t:element="book" t:wrapper="fo:block">
<t:titlepage-content t:side="recto">
<title
t:named-template="division.title"
param:node="ancestor-or-self::book[1]"
text-align="center"
font-size="&hsize5;"
space-before="&hsize5space;"
font-weight="bold"
font-family="{$title.fontset}"/>
<subtitle
text-align="center"
font-size="&hsize4;"
space-before="&hsize4space;"
font-family="{$title.fontset}"/>
<!-- <corpauthor space-before="0.5em"
font-size="&hsize2;"/>
<authorgroup space-before="0.5em"
font-size="&hsize2;"/>
<author space-before="0.5em"
font-size="&hsize2;"/> -->
<mediaobject space-before="2em" space-after="2em"/>
<releaseinfo space-before="5em" font-size="&hsize2;"/>
<copyright space-before="1.5em"
font-weight="normal"
font-size="8"/>
<legalnotice space-before="5em"
font-weight="normal"
font-style="italic"
font-size="8"/>
<othercredit space-before="2em"
font-weight="normal"
font-size="8"/>
<pubdate space-before="0.5em"/>
<revision space-before="0.5em"/>
<revhistory space-before="0.5em"/>
<abstract space-before="0.5em"
text-align="start"
margin-left="0.5in"
margin-right="0.5in"
font-family="{$body.fontset}"/>
</t:titlepage-content>
<t:titlepage-content t:side="verso">
</t:titlepage-content>
<t:titlepage-separator>
</t:titlepage-separator>
<t:titlepage-before t:side="recto">
</t:titlepage-before>
<t:titlepage-before t:side="verso">
</t:titlepage-before>
</t:titlepage>
<!-- ==================================================================== -->
</t:templates>