Moved everything from mvn-build to trunk root.
BIN
core/docs/reference/images/admons/blank.png
Normal file
|
After Width: | Height: | Size: 374 B |
BIN
core/docs/reference/images/admons/caution.gif
Normal file
|
After Width: | Height: | Size: 743 B |
BIN
core/docs/reference/images/admons/caution.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
core/docs/reference/images/admons/caution.tif
Normal file
BIN
core/docs/reference/images/admons/draft.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
core/docs/reference/images/admons/home.gif
Normal file
|
After Width: | Height: | Size: 321 B |
BIN
core/docs/reference/images/admons/home.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
core/docs/reference/images/admons/important.gif
Normal file
|
After Width: | Height: | Size: 1003 B |
BIN
core/docs/reference/images/admons/important.png
Normal file
|
After Width: | Height: | Size: 722 B |
BIN
core/docs/reference/images/admons/important.tif
Normal file
BIN
core/docs/reference/images/admons/next.gif
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
core/docs/reference/images/admons/next.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
core/docs/reference/images/admons/note.gif
Normal file
|
After Width: | Height: | Size: 580 B |
BIN
core/docs/reference/images/admons/note.png
Normal file
|
After Width: | Height: | Size: 490 B |
BIN
core/docs/reference/images/admons/note.tif
Normal file
BIN
core/docs/reference/images/admons/prev.gif
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
core/docs/reference/images/admons/prev.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
core/docs/reference/images/admons/tip.gif
Normal file
|
After Width: | Height: | Size: 598 B |
BIN
core/docs/reference/images/admons/tip.png
Normal file
|
After Width: | Height: | Size: 449 B |
BIN
core/docs/reference/images/admons/tip.tif
Normal file
BIN
core/docs/reference/images/admons/toc-blank.png
Normal file
|
After Width: | Height: | Size: 318 B |
BIN
core/docs/reference/images/admons/toc-minus.png
Normal file
|
After Width: | Height: | Size: 259 B |
BIN
core/docs/reference/images/admons/toc-plus.png
Normal file
|
After Width: | Height: | Size: 264 B |
BIN
core/docs/reference/images/admons/up.gif
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
core/docs/reference/images/admons/up.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
core/docs/reference/images/admons/warning.gif
Normal file
|
After Width: | Height: | Size: 743 B |
BIN
core/docs/reference/images/admons/warning.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
core/docs/reference/images/admons/warning.tif
Normal file
BIN
core/docs/reference/images/callouts/1.gif
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
core/docs/reference/images/callouts/1.png
Normal file
|
After Width: | Height: | Size: 329 B |
BIN
core/docs/reference/images/callouts/10.gif
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
core/docs/reference/images/callouts/10.png
Normal file
|
After Width: | Height: | Size: 361 B |
BIN
core/docs/reference/images/callouts/11.gif
Normal file
|
After Width: | Height: | Size: 244 B |
BIN
core/docs/reference/images/callouts/11.png
Normal file
|
After Width: | Height: | Size: 565 B |
BIN
core/docs/reference/images/callouts/12.gif
Normal file
|
After Width: | Height: | Size: 244 B |
BIN
core/docs/reference/images/callouts/12.png
Normal file
|
After Width: | Height: | Size: 617 B |
BIN
core/docs/reference/images/callouts/13.gif
Normal file
|
After Width: | Height: | Size: 244 B |
BIN
core/docs/reference/images/callouts/13.png
Normal file
|
After Width: | Height: | Size: 623 B |
BIN
core/docs/reference/images/callouts/14.gif
Normal file
|
After Width: | Height: | Size: 244 B |
BIN
core/docs/reference/images/callouts/14.png
Normal file
|
After Width: | Height: | Size: 411 B |
BIN
core/docs/reference/images/callouts/15.gif
Normal file
|
After Width: | Height: | Size: 244 B |
BIN
core/docs/reference/images/callouts/15.png
Normal file
|
After Width: | Height: | Size: 640 B |
BIN
core/docs/reference/images/callouts/2.gif
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
core/docs/reference/images/callouts/2.png
Normal file
|
After Width: | Height: | Size: 353 B |
BIN
core/docs/reference/images/callouts/3.gif
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
core/docs/reference/images/callouts/3.png
Normal file
|
After Width: | Height: | Size: 350 B |
BIN
core/docs/reference/images/callouts/4.gif
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
core/docs/reference/images/callouts/4.png
Normal file
|
After Width: | Height: | Size: 345 B |
BIN
core/docs/reference/images/callouts/5.gif
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
core/docs/reference/images/callouts/5.png
Normal file
|
After Width: | Height: | Size: 348 B |
BIN
core/docs/reference/images/callouts/6.gif
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
core/docs/reference/images/callouts/6.png
Normal file
|
After Width: | Height: | Size: 355 B |
BIN
core/docs/reference/images/callouts/7.gif
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
core/docs/reference/images/callouts/7.png
Normal file
|
After Width: | Height: | Size: 344 B |
BIN
core/docs/reference/images/callouts/8.gif
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
core/docs/reference/images/callouts/8.png
Normal file
|
After Width: | Height: | Size: 357 B |
BIN
core/docs/reference/images/callouts/9.gif
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
core/docs/reference/images/callouts/9.png
Normal file
|
After Width: | Height: | Size: 357 B |
20
core/docs/reference/readme.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
This project uses the 'DocBook XSL distribution' for HTML and PDF
|
||||
generation of project reference documentation.
|
||||
|
||||
This project's build.xml file contains targets to generate the
|
||||
project reference documentation.
|
||||
|
||||
To generate project documentation, execute one of the following
|
||||
build targets:
|
||||
|
||||
* doc-all - generate documentation in all supported formats
|
||||
* doc-pdf - generate the PDF documentation
|
||||
* doc-html - generate the HTML documentation
|
||||
* doc-htmlsingle - generate single page HTML documentation
|
||||
* doc-clean - clean any output directories for docs
|
||||
|
||||
For generation to complete successfully, you must have first extracted
|
||||
the .jar libraries contained in this archive:
|
||||
- http://static.springframework.org/spring/files/docbook-reference-libs.zip
|
||||
... to ${basedir}/docs/reference. If you have not yet done so, download this file
|
||||
and unzip the contents of the archive into ${basedir}/docs/reference.
|
||||
385
core/docs/reference/src/basic.xml
Normal file
@@ -0,0 +1,385 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="basic">
|
||||
<title>Basic Operations</title>
|
||||
|
||||
<sect1 id="basic-searches">
|
||||
<title>Search and Lookup Using AttributesMapper</title>
|
||||
|
||||
<para>In this example we will use an <literal>AttributesMapper</literal>
|
||||
to easily build a List of all common names of all person objects.</para>
|
||||
|
||||
<example>
|
||||
<title>AttributesMapper that returns a single attribute</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
|
||||
public void setLdapTemplate(LdapTemplate ldapTemplate) {
|
||||
this.ldapTemplate = ldapTemplate;
|
||||
}
|
||||
|
||||
public List getAllPersonNames() {
|
||||
return ldapTemplate.search(
|
||||
"", "(objectclass=person)",
|
||||
<emphasis role="bold"> new AttributesMapper() {
|
||||
public Object mapFromAttributes(Attributes attrs)
|
||||
throws NamingException {
|
||||
return attrs.get("cn").get();
|
||||
}
|
||||
}</emphasis>);
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>The inline implementation of <literal>AttributesMapper</literal>
|
||||
just gets the desired attribute value from the
|
||||
<literal>Attributes</literal> and returns it. Internally,
|
||||
<literal>LdapTemplate</literal> iterates over all entries found, calling
|
||||
the given <literal>AttributesMapper</literal> for each entry, and collects
|
||||
the results in a list. The list is then returned by the
|
||||
<literal>search</literal> method.</para>
|
||||
|
||||
<para>Note that the <literal>AttributesMapper</literal> implementation
|
||||
could easily be modified to return a full <literal>Person</literal>
|
||||
object:</para>
|
||||
|
||||
<example>
|
||||
<title>AttributesMapper that returns a Person object</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
...
|
||||
<emphasis role="bold"> private class PersonAttributesMapper implements AttributesMapper {
|
||||
public Object mapFromAttributes(Attributes attrs) throws NamingException {
|
||||
Person person = new Person();
|
||||
person.setFullName((String)attrs.get("cn").get());
|
||||
person.setLastName((String)attrs.get("sn").get());
|
||||
person.setDescription((String)attrs.get("description").get());
|
||||
return person;
|
||||
}
|
||||
}
|
||||
</emphasis>
|
||||
public List getAllPersons() {
|
||||
return ldapTemplate.search("", "(objectclass=person)", <emphasis
|
||||
role="bold">new PersonAttributesMapper()</emphasis>);
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>If you have the distinguished name (<literal>dn</literal>) that
|
||||
identifies an entry, you can retrieve the entry directly, without
|
||||
searching for it. This is called a <emphasis>lookup</emphasis> in Java
|
||||
LDAP. The following example shows how a lookup results in a Person
|
||||
object:</para>
|
||||
|
||||
<example>
|
||||
<title>A lookup resulting in a Person object</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
...
|
||||
public Person findPerson(String dn) {
|
||||
return (Person) ldapTemplate.lookup(dn, new PersonAttributesMapper());
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>This will look up the specified <literal>dn</literal> and pass the
|
||||
found attributes to the supplied <literal>AttributesMapper</literal>, in
|
||||
this case resulting in a <literal>Person</literal> object.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="basic-filters">
|
||||
<title>Building Dynamic Filters</title>
|
||||
|
||||
<para>We can build dynamic filters to use in searches, using the classes
|
||||
from the <literal>org.springframework.ldap.filter</literal>
|
||||
package. Let's say that we want the following filter:
|
||||
<literal>(&(objectclass=person)(sn=?))</literal>, where we want the
|
||||
<literal>?</literal> to be replaced with the value of the parameter
|
||||
<literal>lastName</literal>. This is how we do it using the filter support
|
||||
classes:</para>
|
||||
|
||||
<example>
|
||||
<title>Building a search filter dynamically</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
...
|
||||
public List getPersonNamesByLastName(String lastName) {
|
||||
<emphasis role="bold"> AndFilter filter = new AndFilter();
|
||||
filter.and(new EqualsFilter("objectclass", "person"));
|
||||
filter.and(new EqualsFilter("sn", lastName));
|
||||
</emphasis> return ldapTemplate.search(
|
||||
"", <emphasis role="bold">filter.encode()</emphasis>,
|
||||
new AttributesMapper() {
|
||||
public Object mapFromAttributes(Attributes attrs)
|
||||
throws NamingException {
|
||||
return attrs.get("cn").get();
|
||||
}
|
||||
});
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>To perform a wildcard search, it's possible to use the
|
||||
<literal>WhitespaceWildcardsFilter</literal>:</para>
|
||||
|
||||
<example>
|
||||
<title>Building a wildcard search filter</title>
|
||||
|
||||
<programlisting>AndFilter filter = new AndFilter();
|
||||
filter.and(new EqualsFilter("objectclass", "person"));
|
||||
filter.and(new WhitespaceWildcardsFilter("cn", cn));</programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
<note>
|
||||
In addition to simplifying building of complex search filters,
|
||||
the <literal>Filter</literal> classes also provide proper escaping
|
||||
of any unsafe characters. This prevents "ldap injection",
|
||||
where a user might use such characters to inject unwanted operations
|
||||
into your LDAP operations.
|
||||
</note>
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Building Dynamic Distinguished Names</title>
|
||||
|
||||
<para>The standard <ulink
|
||||
url="http://java.sun.com/j2se/1.5.0/docs/api/javax/naming/Name.html">Name</ulink>
|
||||
interface represents a generic name, which is basically an ordered
|
||||
sequence of components. The <literal>Name</literal> interface also
|
||||
provides operations on that sequence; e.g., <literal>add</literal> or
|
||||
<literal>remove</literal>. LdapTemplate provides an implementation of the
|
||||
<literal>Name</literal> interface: <literal>DistinguishedName</literal>.
|
||||
Using this class will greatly simplify building distinguished names,
|
||||
especially considering the sometimes complex rules regarding escapings and
|
||||
encodings. As with the <literal>Filter</literal> classes this helps preventing
|
||||
potentially malicious data being injected into your LDAP operations.
|
||||
</para>
|
||||
<para>
|
||||
The following example illustrates how
|
||||
<literal>DistinguishedName</literal> can be used to dynamically construct
|
||||
a distinguished name:</para>
|
||||
|
||||
<example>
|
||||
<title>Building a distinguished name dynamically</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
import org.springframework.ldap.core.support.DistinguishedName;
|
||||
import javax.naming.Name;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
public static final String BASE_DN = "dc=example,dc=com";
|
||||
...
|
||||
protected Name buildDn(Person p) {
|
||||
<emphasis role="bold"> DistinguishedName dn = new DistinguishedName(BASE_DN);
|
||||
dn.add("c", p.getCountry());
|
||||
dn.add("ou", p.getCompany());
|
||||
dn.add("cn", p.getFullname());
|
||||
</emphasis> return dn;
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>Assuming that a Person has the following attributes:</para>
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>country</literal></entry>
|
||||
|
||||
<entry>Sweden</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>company</literal></entry>
|
||||
|
||||
<entry>Some Company</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>fullname</literal></entry>
|
||||
|
||||
<entry>Some Person</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
||||
<para>The code above would then result in the following distinguished
|
||||
name:</para>
|
||||
|
||||
<para><programlisting>cn=Some Person, ou=Some Company, c=Sweden, dc=example, dc=com</programlisting></para>
|
||||
|
||||
<para>In Java 5, there is an implementation of the Name interface: <ulink
|
||||
url="http://java.sun.com/j2se/1.5.0/docs/api/javax/naming/ldap/LdapName.html">LdapName</ulink>.
|
||||
If you are in the Java 5 world, you might as well use
|
||||
<literal>LdapName</literal>. However, you may still use
|
||||
<literal>DistinguishedName</literal> if you so wish.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="basic-binding-unbinding">
|
||||
<title>Binding and Unbinding</title>
|
||||
|
||||
<sect2 id="basic-binding-data">
|
||||
<title>Binding Data</title>
|
||||
|
||||
<para>Inserting data in Java LDAP is called binding. In order to do
|
||||
that, a distinguished name that uniquely identifies the new entry is
|
||||
required. The following example shows how data is bound using
|
||||
LdapTemplate:</para>
|
||||
|
||||
<example>
|
||||
<title>Binding data using Attributes</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
...
|
||||
public void create(Person p) {
|
||||
Name dn = buildDn(p);
|
||||
<emphasis role="bold"> ldapTemplate.bind(dn, null, buildAttributes(p));
|
||||
</emphasis> }
|
||||
|
||||
private Attributes buildAttributes(Person p) {
|
||||
Attributes attrs = new BasicAttributes();
|
||||
BasicAttribute ocattr = new BasicAttribute("objectclass");
|
||||
ocattr.add("top");
|
||||
ocattr.add("person");
|
||||
attrs.put(ocattr);
|
||||
attrs.put("cn", "Some Person");
|
||||
attrs.put("sn", "Person");
|
||||
return attrs;
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>The Attributes building is--while dull and verbose--sufficient for
|
||||
many purposes. It is, however, possible to simplify the binding
|
||||
operation further, which will be described in <xref
|
||||
linkend="dirobjectfactory" />.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="basic-unbinding-data">
|
||||
<title>Unbinding Data</title>
|
||||
|
||||
<para>Removing data in Java LDAP is called unbinding. A distinguished
|
||||
name (dn) is required to identify the entry, just as in the binding
|
||||
operation. The following example shows how data is unbound using
|
||||
LdapTemplate:</para>
|
||||
|
||||
<example>
|
||||
<title>Unbinding data</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
...
|
||||
public void delete(Person p) {
|
||||
Name dn = buildDn(p);
|
||||
<emphasis role="bold"> ldapTemplate.unbind(dn);
|
||||
</emphasis> }
|
||||
}</programlisting>
|
||||
</example>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="basic-modifying">
|
||||
<title>Modifying</title>
|
||||
|
||||
<para>In Java LDAP, data can be modified in two ways: either using
|
||||
<emphasis>rebind</emphasis> or
|
||||
<emphasis>modifyAttributes</emphasis>.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Modifying using <literal>rebind</literal></title>
|
||||
|
||||
<para>A <literal>rebind</literal> is a very crude way to modify data.
|
||||
It's basically an <literal>unbind</literal> followed by a
|
||||
<literal>bind</literal>. It looks like this:</para>
|
||||
|
||||
<example>
|
||||
<title>Modifying using rebind</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
...
|
||||
public void update(Person p) {
|
||||
Name dn = buildDn(p);
|
||||
<emphasis role="bold"> ldapTemplate.rebind(dn, null, buildAttributes(p));
|
||||
</emphasis> }
|
||||
}</programlisting>
|
||||
</example>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="modify-modifyAttributes">
|
||||
<title>Modifying using <literal>modifyAttributes</literal></title>
|
||||
|
||||
<para>If only the modified attributes should be replaced, there is a
|
||||
method called <literal>modifyAttributes</literal> that takes an array of
|
||||
modifications:</para>
|
||||
|
||||
<example>
|
||||
<title>Modifying using modifyAttributes</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
...
|
||||
public void updateDescription(Person p) {
|
||||
Name dn = buildDn(p);
|
||||
Attribute attr = new BasicAttribute("description", p.getDescription())
|
||||
ModificationItem item = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr);
|
||||
<emphasis role="bold"> ldapTemplate.modifyAttributes(dn, new ModificationItem[] {item});
|
||||
</emphasis> }
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>Building <literal>Attributes</literal> and
|
||||
<literal>ModificationItem</literal> arrays is a lot of work, but as you
|
||||
will see in <xref linkend="dirobjectfactory" />, the update operations
|
||||
can be simplified.</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="samples">
|
||||
<title>Sample applications</title>
|
||||
|
||||
<para>It is recommended that you review the Spring LDAP sample
|
||||
applications included in the release distribution for best-practice
|
||||
illustrations of the features of this library. A description of each
|
||||
sample is provided below:</para>
|
||||
|
||||
<para><orderedlist>
|
||||
<listitem>
|
||||
<para>spring-ldap-person - the sample demonstrating most
|
||||
features.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>spring-ldap-article - the sample application that was written
|
||||
to accompany a <ulink
|
||||
url="http://today.java.net/pub/a/today/2006/04/18/ldaptemplate-java-ldap-made-simple.html">java.net
|
||||
article</ulink> about Spring LDAP.</para>
|
||||
</listitem>
|
||||
</orderedlist></para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
259
core/docs/reference/src/configuration.xml
Normal file
@@ -0,0 +1,259 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="configuration">
|
||||
<title>Configuration</title>
|
||||
|
||||
<sect1 id="context-source-configuration">
|
||||
<title>ContextSource Configuration</title>
|
||||
|
||||
<para>There are several properties in <literal>AbstractContextSource</literal>
|
||||
(superclass of <literal>DirContextSource</literal> and <literal>LdapContextSource</literal>)
|
||||
that can be used to modify its behaviour.</para>
|
||||
|
||||
<sect2 id="dir-context-url">
|
||||
<title>LDAP Server URLs</title>
|
||||
|
||||
<para>The URL of the LDAP server is specified using the <literal>url</literal> property.
|
||||
The URL should be in the format <literal>ldap://myserver.example.com:389</literal>.
|
||||
For SSL access, use the <literal>ldaps</literal> protocol and the appropriate port, e.g.
|
||||
<literal>ldaps://myserver.example.com:636</literal></para>
|
||||
<para>It is possible to configure multiple alternate LDAP servers using the
|
||||
<literal>urls</literal> property. In this case, supply all server urls in a String
|
||||
array to the <literal>urls</literal> property.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="dir-context-base">
|
||||
<title>Base LDAP path</title>
|
||||
|
||||
<para>It is possible to specify the root context for all LDAP operations using the
|
||||
<literal>base</literal> property of <literal>AbstractContextSource</literal>.
|
||||
When a value has been specified to this property, all Distinguished Names supplied to and received from LDAP operations
|
||||
will be relative to the LDAP path supplied. This can significantly simplify working against the LDAP
|
||||
tree; however there are several occations when you will need to have access to the base path.
|
||||
For more information on this, please refer to <xref linkend="base-context-configuration" /></para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="dir-context-authentication">
|
||||
<title>Authentication</title>
|
||||
|
||||
<para>Authenticated contexts are created for both read-only and
|
||||
read-write operations by default. You specify
|
||||
<literal>userDn</literal> and <literal>password</literal> of the LDAP
|
||||
user to be used for authentication on the
|
||||
<literal>ContextSource</literal>.</para>
|
||||
|
||||
<para><note>
|
||||
<para>The <literal>userDn</literal> needs to be the full
|
||||
Distinguished Name (DN) of the user.</para>
|
||||
</note></para>
|
||||
|
||||
<para>Some LDAP server setups allow anonymous read-only access. If you
|
||||
want to use anonymous Contexts for read-only operations, set the
|
||||
<literal>anonymousReadOnly</literal> property to
|
||||
<literal>true</literal>.<literal></literal></para>
|
||||
|
||||
<sect3>
|
||||
<title>Custom Authentication Using Acegi</title>
|
||||
|
||||
<para>While the user name (i.e. user DN) and password used for
|
||||
creating an authenticated <literal>Context</literal> are static by
|
||||
default - the ones set on the <literal>ContextSource</literal> on
|
||||
startup will be used throughout the lifetime of the
|
||||
<literal>ContextSource</literal> - there are however several cases in
|
||||
which this is not the desired behaviour. A common scenario is that the
|
||||
principal and credentials of the current user should be used when
|
||||
executing LDAP operations for that user. The default behaviour can be
|
||||
modified by supplying a custom <literal>AuthenticationSource</literal>
|
||||
implementation to the <literal>ContextSource</literal> on startup,
|
||||
instead of explicitly specifying the <literal>userDn</literal> and
|
||||
<literal>password</literal>. The
|
||||
<literal>AuthenticationSource</literal> will be queried by the
|
||||
<literal>ContextSource</literal> for principal and credentials each
|
||||
time an authenticated <literal>Context</literal> is to be
|
||||
created.</para>
|
||||
|
||||
<para>To use the authentication information of the currently logged in
|
||||
user using <ulink url="http://acegisecurity.org/">Acegi
|
||||
Security</ulink>, use the
|
||||
<literal>AcegiAuthenticationSource</literal>:</para>
|
||||
|
||||
<example>
|
||||
<title>The Spring bean definition for an
|
||||
AcegiAuthenticationSource</title>
|
||||
|
||||
<programlisting><beans>
|
||||
...
|
||||
<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
|
||||
<property name="url" value="ldap://localhost:389" />
|
||||
<property name="base" value="dc=example,dc=com" />
|
||||
<property name="authenticationSource" ref="acegiAuthenticationSource" />
|
||||
</bean>
|
||||
|
||||
<bean id="acegiAuthenticationSource"
|
||||
class="org.springframework.ldap.authentication.AcegiAuthenticationSource" />
|
||||
...
|
||||
</beans></programlisting>
|
||||
</example>
|
||||
|
||||
<note>
|
||||
<para>We don't specify any <literal>userDn</literal> or
|
||||
<literal>password</literal> to our <literal>ContextSource</literal>
|
||||
when using an <literal>AuthenticationSource</literal> - these
|
||||
properties are needed only when the default behaviour is
|
||||
used.</para>
|
||||
</note>
|
||||
|
||||
<note>
|
||||
<para>When using the <literal>AcegiAuthenticationSource</literal>
|
||||
you need to use Acegi's
|
||||
<literal>LdapAuthenticationProvider</literal> to authenticate the
|
||||
users against LDAP.</para>
|
||||
</note>
|
||||
</sect3>
|
||||
|
||||
<sect3>
|
||||
<title>Default Authentication</title>
|
||||
|
||||
<para>When using <literal>AcegiAuthenticationSource</literal>,
|
||||
authenticated contexts will only be possible to create once the user
|
||||
is logged in using Acegi. To use default authentication information
|
||||
when no user is logged in, use the
|
||||
<literal>DefaultValuesAuthenticationSourceDecorator</literal>:</para>
|
||||
|
||||
<example>
|
||||
<title>Configuring a
|
||||
DefaultValuesAuthenticationSourceDecorator</title>
|
||||
|
||||
<programlisting><beans>
|
||||
...
|
||||
<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
|
||||
<property name="url" value="ldap://localhost:389" />
|
||||
<property name="base" value="dc=example,dc=com" />
|
||||
<property name="authenticationSource" ref="authenticationSource" />
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationSource"
|
||||
class="org.springframework.ldap.authentication.DefaultValuesAuthenticationSourceDecorator">
|
||||
<property name="target" ref="acegiAuthenticationSource" />
|
||||
<property name="defaultUser" value="cn=myDefaultUser" />
|
||||
<property name="defaultPassword" value="pass" />
|
||||
</bean>
|
||||
|
||||
<bean id="acegiAuthenticationSource"
|
||||
class="org.springframework.ldap.authentication.AcegiAuthenticationSource" />
|
||||
...
|
||||
</beans></programlisting>
|
||||
</example>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="context-source-pooling">
|
||||
<title>Pooling</title>
|
||||
|
||||
<para>LDAP connection pooling can be turned on/off using the
|
||||
<literal>pooled</literal> flag. Default is <literal>true</literal>. The
|
||||
configuration of LDAP connection pooling is managed using
|
||||
<literal>System</literal> properties, so this needs to be handled
|
||||
manually. Details of pooling configuration can be found <ulink
|
||||
url="http://java.sun.com/products/jndi/tutorial/ldap/connect/config.html">here</ulink>.</para>
|
||||
|
||||
</sect2>
|
||||
<sect2 id="context-source-advanced">
|
||||
<title>Advanced ContextSource Configuration</title>
|
||||
<sect3 id="context-source-context-factory">
|
||||
<title>Alternate ContextFactory</title>
|
||||
|
||||
<para>It is possible to configure the <literal>ContextFactory</literal> that the
|
||||
<literal>ContextSource</literal> is to use when creating Contexts using the
|
||||
<literal>contextFactory</literal> property. The default value is
|
||||
<literal>com.sun.jndi.ldap.LdapCtxFactory</literal>.</para>
|
||||
</sect3>
|
||||
<sect3 id="context-source-object-factory">
|
||||
<title>Custom DirObjectFactory</title>
|
||||
|
||||
<para>As described in <xref linkend="dirobjectfactory" />, a <literal>DirObjectFactory</literal>
|
||||
can be used to translate the <literal>Attributes</literal> of found Contexts
|
||||
to a more useful <literal>DirContext</literal> implementation. This can be
|
||||
configured using the <literal>dirObjectFactory</literal> property. You can use
|
||||
this property if you have your own, custom <literal>DirObjectFactory</literal> implementation.</para>
|
||||
<para>The default value is <literal>DefaultDirObjectFactory</literal>.</para>
|
||||
</sect3>
|
||||
<sect3 id="context-source-custom-env-properties">
|
||||
<title>Custom DirContext Environment Properties</title>
|
||||
|
||||
<para>In some cases the user might want to specify additional environment setup properties
|
||||
in addition to the ones directly configurable from <literal>AbstractContextSource</literal>.
|
||||
Such properties should be set in a <literal>Map</literal> and supplied to
|
||||
the <literal>baseEnvironmentProperties</literal> property.</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1 id="ldap-template-configuration">
|
||||
<title>LdapTemplate Configuration</title>
|
||||
|
||||
<sect2 id="ldap-template-ignore-partial-result">
|
||||
<title>Ignoring PartialResultExceptions</title>
|
||||
|
||||
<para>Some Active Directory (AD) servers are unable to automatically following
|
||||
referrals, which often leads to a <literal>PartialResultException</literal> being
|
||||
thrown in searches. You can specify that <literal>PartialResultException</literal>
|
||||
is to be ignored by setting the <literal>ignorePartialResultException</literal>
|
||||
property to <literal>true</literal>.
|
||||
<note>This causes all referrals to be ignored, and no notice will be given that
|
||||
a <literal>PartialResultException</literal> has been encountered.
|
||||
There is currently no way of manually following referrals using LdapTemplate.</note></para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1 id="base-context-configuration">
|
||||
<title>Obtaining a reference to the base LDAP path</title>
|
||||
<para>As described above, a base LDAP path may be supplied to the <literal>ContextSource</literal>,
|
||||
specifying the root in the LDAP tree to which all operations will be relative. This means that
|
||||
you will only be working with relative distinguished names throughout your system, which is
|
||||
typically rather handy. There are however some cases in which you will need to have access
|
||||
to the base path in order to be able to construct full DNs, relative to the actual root of the LDAP tree.
|
||||
One example would be when working with LDAP groups (e.g. <literal>groupOfNames</literal> objectclass),
|
||||
in which case each group member attribute value will need to be the full DN of the referenced member.</para>
|
||||
<para>For that reason, Spring LDAP has a mechanism by which any Spring controlled bean may be supplied
|
||||
the base path on startup. For beans to be notified of the base path, two things need to be in place:
|
||||
First of all, the bean that wants the base path reference needs to implement the
|
||||
<literal>BaseLdapPathAware</literal> interface. Secondly, a <literal>BaseLdapPathBeanPostProcessor</literal>
|
||||
needs to be defined in the application context</para>
|
||||
<example>
|
||||
<title>Implementing <literal>BaseLdapPathAware</literal></title>
|
||||
|
||||
<programlisting>package com.example.service;
|
||||
|
||||
public class PersonService implements PersonService, <emphasis role="bold">BaseLdapPathAware</emphasis> {
|
||||
...
|
||||
<emphasis role="bold">private DistinguishedName basePath;
|
||||
|
||||
public void setBaseLdapPath(DistinguishedName basePath) {
|
||||
this.basePath = basePath;
|
||||
}</emphasis>
|
||||
...
|
||||
private DistinguishedName getFullPersonDn(Person person) {
|
||||
return new DistinguishedName(<emphasis role="bold">basePath</emphasis>).append(person.getDn());
|
||||
}
|
||||
...
|
||||
}</programlisting>
|
||||
</example>
|
||||
<example>
|
||||
<title>Specifying a <literal>BaseLdapPathBeanPostProcessor</literal> in your <literal>ApplicationContext</literal></title>
|
||||
|
||||
<programlisting><beans>
|
||||
...
|
||||
<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
|
||||
<property name="url" value="ldap://localhost:389" />
|
||||
<property name="base" value="dc=example,dc=com" />
|
||||
<property name="acegiAuthenticationSource" ref="authenticationSource" />
|
||||
</bean>
|
||||
...
|
||||
<emphasis role="bold"><bean class="org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor" /></emphasis>
|
||||
</beans>
|
||||
</programlisting>
|
||||
</example>
|
||||
<para>The default behaviour of the <literal>BaseLdapPathBeanPostProcessor</literal> is to use the base path of the single
|
||||
defined <literal>BaseLdapPathSource</literal> (<literal>AbstractContextSource</literal> )in the <literal>ApplicationContext</literal>.
|
||||
If more than one <literal>BaseLdapPathSource</literal> is defined, you will need to specify which one to use with the
|
||||
<literal>baseLdapPathSourceName</literal> property.</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
200
core/docs/reference/src/contextprocessor.xml
Normal file
@@ -0,0 +1,200 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="processor">
|
||||
<title>Processing the DirContext</title>
|
||||
|
||||
<sect1 id="processor-overview">
|
||||
<title>Custom DirContext Pre/Postprocessing</title>
|
||||
|
||||
<para>In some situations, one would like to perform operations on the
|
||||
<literal>DirContext</literal> before and after the search operation. The
|
||||
interface that is used for this is called
|
||||
<literal>DirContextProcessor</literal>:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>public interface DirContextProcessor {
|
||||
public void preProcess(DirContext ctx) throws NamingException;
|
||||
public void postProcess(DirContext ctx) throws NamingException;
|
||||
}</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>The <literal>LdapTemplate</literal> class has a search method that
|
||||
takes a <literal>DirContextProcessor</literal>:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>public void search(SearchExecutor se, NameClassPairCallbackHandler handler,
|
||||
DirContextProcessor processor) throws DataAccessException;</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>Before the search operation, the <literal>preProcess</literal>
|
||||
method is called on the given <literal>DirContextProcessor</literal>
|
||||
instance. After the search has been executed and the resulting
|
||||
<literal>NamingEnumeration</literal> has been processed, the
|
||||
<literal>postProcess</literal> method is called. This enables a user to
|
||||
perform operations on the <literal>DirContext</literal> to be used in the
|
||||
search, and to check the <literal>DirContext</literal> when the search has
|
||||
been performed. This can be very useful for example when handling request
|
||||
and response controls.</para>
|
||||
|
||||
<para>There are also a few convenience methods for those that don't need a
|
||||
custom <literal>SearchExecutor</literal>:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>public void search(Name base, String filter,
|
||||
SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor)
|
||||
|
||||
public void search(String base, String filter,
|
||||
SearchControls controls, NameClassPairCallbackHandler handler, DirContextProcessor processor)
|
||||
|
||||
public void search(Name base, String filter,
|
||||
SearchControls controls, AttributesMapper mapper, DirContextProcessor processor)
|
||||
|
||||
public void search(String base, String filter,
|
||||
SearchControls controls, AttributesMapper mapper, DirContextProcessor processor)
|
||||
|
||||
public void search(Name base, String filter,
|
||||
SearchControls controls, ContextMapper mapper, DirContextProcessor processor)
|
||||
|
||||
public void search(String base, String filter,
|
||||
SearchControls controls, ContextMapper mapper, DirContextProcessor processor)</programlisting>
|
||||
</informalexample>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="processor-others">
|
||||
<title>Implementing a Request Control DirContextProcessor</title>
|
||||
|
||||
<para>The LDAPv3 protocol uses Controls to send and receive additional
|
||||
data to affect the behavior of predefined operations. In order to simplify
|
||||
the implementation of a request control
|
||||
<literal>DirContextProcessor</literal>, Spring LDAP provides the base
|
||||
class <literal>AbstractRequestControlDirContextProcessor</literal>. This
|
||||
class handles the retrieval of the current request controls from the
|
||||
<literal>LdapContext</literal>, calls a template method for creating a
|
||||
request control, and adds it to the <literal>LdapContext</literal>. All
|
||||
you have to do in the subclass is to implement the template method
|
||||
<literal>createRequestControl</literal>, and of course the
|
||||
<literal>postProcess</literal> method for performing whatever you need to
|
||||
do after the search.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>public abstract class AbstractRequestControlDirContextProcessor implements
|
||||
DirContextProcessor {
|
||||
|
||||
public void preProcess(DirContext ctx) throws NamingException {
|
||||
...
|
||||
}
|
||||
|
||||
public abstract Control createRequestControl();
|
||||
}</programlisting>
|
||||
|
||||
<para>A typical <literal>DirContextProcessor</literal> will be similar to the following:</para>
|
||||
</informalexample>
|
||||
|
||||
<example>
|
||||
<title>A request control DirContextProcessor implementation</title>
|
||||
|
||||
<programlisting>package com.example.control;
|
||||
|
||||
public class MyCoolRequestControl extends AbstractRequestControlDirContextProcessor {
|
||||
private static final boolean CRITICAL_CONTROL = true;
|
||||
private MyCoolCookie cookie;
|
||||
...
|
||||
public MyCoolCookie getCookie() {
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public Control createRequestControl() {
|
||||
return new SomeCoolControl(cookie.getCookie(), CRITICAL_CONTROL);
|
||||
}
|
||||
|
||||
public void postProcess(DirContext ctx) throws NamingException {
|
||||
LdapContext ldapContext = (LdapContext) ctx;
|
||||
Control[] responseControls = ldapContext.getResponseControls();
|
||||
|
||||
for (int i = 0; i < responseControls.length; i++) {
|
||||
if (responseControls[i] instanceof SomeCoolResponseControl) {
|
||||
SomeCoolResponseControl control = (SomeCoolResponseControl) responseControls[i];
|
||||
this.cookie = new MyCoolCookie(control.getCookie());
|
||||
}
|
||||
}
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<note>
|
||||
<para>Make sure you use <literal>LdapContextSource</literal> when you
|
||||
use Controls. The <literal><ulink
|
||||
url="http://java.sun.com/j2se/1.5.0/docs/api/javax/naming/ldap/Control.html">Control</ulink></literal>
|
||||
interface is specific for LDAPv3 and requires that
|
||||
<literal>LdapContext</literal> is used instead of
|
||||
<literal>DirContext</literal>. If an
|
||||
<literal>AbstractRequestControlDirContextProcessor</literal> subclass is
|
||||
called with an argument that is not an <literal>LdapContext</literal>,
|
||||
it will throw an <literal>IllegalArgumentException</literal>.</para>
|
||||
</note>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Paged Search Results</title>
|
||||
|
||||
<para>Some searches may return large numbers of results. When there is no
|
||||
easy way to filter out a smaller amount, it would be convenient to have
|
||||
the server return only a certain number of results each time it is called.
|
||||
This is known as <emphasis>paged search results</emphasis>. Each "page" of
|
||||
the result could then be displayed at the time, with links to the next and
|
||||
previous page. Without this functionality, the client must either manually
|
||||
limit the search result into pages, or retrieve the whole result and then
|
||||
chop it into pages of suitable size. The former would be rather
|
||||
complicated, and the latter would be consuming unnecessary amounts of
|
||||
memory.</para>
|
||||
|
||||
<para>Some LDAP servers have support for the
|
||||
<literal>PagedResultsControl</literal>, which requests that the results of
|
||||
a search operation are returned by the LDAP server in pages of a specified
|
||||
size. The user controls the rate at which the pages are returned, simply
|
||||
by the rate at which the searches are called. However, the user must keep
|
||||
track of a <emphasis>cookie</emphasis> between the calls. The server uses
|
||||
this cookie to keep track of where it left off the previous time it was
|
||||
called with a paged results request.</para>
|
||||
|
||||
<para>Spring LDAP provides support for paged results by leveraging the
|
||||
concept for pre- and postprocessing of an <literal>LdapContext</literal> that was discussed
|
||||
in the previous sections. It does so by providing two classes:
|
||||
<literal>PagedResultsRequestControl</literal> and
|
||||
<literal>PagedResultsCookie</literal>. The
|
||||
<literal>PagedResultsRequestControl</literal> class creates a
|
||||
<literal>PagedResultsControl</literal> with the requested page size and
|
||||
adds it to the <literal>LdapContext</literal>. After the search, it gets
|
||||
the <literal>PagedResultsResponseControl</literal> and retrieves two
|
||||
pieces of information from it: the estimated total result size and a
|
||||
cookie. This cookie is a byte array containing information that the server
|
||||
needs the next time it is called with a
|
||||
<literal>PagedResultsControl</literal>. In order to make it easy to store
|
||||
this cookie between searches, Spring LDAP provides the wrapper class
|
||||
<literal>PagedResultsCookie</literal>.</para>
|
||||
|
||||
<para>Below is an example of how the paged search results functionality may
|
||||
be used:</para>
|
||||
|
||||
<example>
|
||||
<title>Paged results using <literal>PagedResultsRequestControl</literal></title>
|
||||
|
||||
<programlisting>public PagedResult getAllPersons(PagedResultsCookie cookie) {
|
||||
PagedResultsRequestControl control = new PagedResultsRequestControl(PAGE_SIZE, cookie);
|
||||
SearchControls searchControls = new SearchControls();
|
||||
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||
|
||||
List persons = ldapTemplate.search("", "objectclass=person", searchControls, control);
|
||||
|
||||
return new PagedResult(persons, control.getCookie());
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>In the first call to this method, <literal>null</literal> will be supplied as
|
||||
the cookie parameter. On subsequent calls the client will need to supply the cookie from
|
||||
the last search (returned wrapped in the <literal>PagedResult</literal>) each time the
|
||||
method is called. When the actual cookie is <literal>null</literal> (i.e.
|
||||
<literal>pagedResult.getCookie().getCookie()</literal> returns <literal>null</literal>),
|
||||
the last batch has been returned from the search.</para>
|
||||
|
||||
</sect1>
|
||||
</chapter>
|
||||
341
core/docs/reference/src/dirobjectfactory.xml
Normal file
@@ -0,0 +1,341 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="dirobjectfactory">
|
||||
<title>Simpler Attribute Access and Manipulation with DirContextAdapter</title>
|
||||
|
||||
<sect1 id="dirobjectfactory-intro">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>A little-known--and probably underestimated--feature of the Java
|
||||
LDAP API is the ability to register a <literal>DirObjectFactory</literal>
|
||||
to automatically create objects from found contexts. One of the reasons
|
||||
why it is seldom used is that you will need an implementation of
|
||||
<literal>DirObjectFactory</literal> that creates instances of a meaningful
|
||||
implementation of <literal>DirContext</literal>. The Spring LDAP library
|
||||
provides the missing pieces: a default implementation of
|
||||
<literal>DirContext</literal> called <literal>DirContextAdapter</literal>,
|
||||
and a corresponding implementation of <literal>DirObjectFactory</literal>
|
||||
called <literal>DefaultDirObjectFactory</literal>. Used together with
|
||||
<literal>DefaultDirObjectFactory</literal>, the
|
||||
<literal>DirContextAdapter</literal> can be a very powerful tool.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Search and Lookup Using ContextMapper</title>
|
||||
|
||||
<para>The <literal>DefaultDirObjectFactory</literal> is registered with
|
||||
the <literal>ContextSource</literal> by default, which means that whenever
|
||||
a context is found in the LDAP tree, its <literal>Attributes</literal> and
|
||||
Distinguished Name (DN) will be used to construct a
|
||||
<literal>DirContextAdapter</literal>. This enables us to use a
|
||||
<literal>ContextMapper</literal> instead of an
|
||||
<literal>AttributesMapper</literal> to transform found values:</para>
|
||||
|
||||
<example>
|
||||
<title>Searching using a ContextMapper</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
...
|
||||
<emphasis role="bold">private static class PersonContextMapper implements ContextMapper {
|
||||
public Object mapFromContext(Object ctx) {
|
||||
DirContextAdapter context = (DirContextAdapter)ctx;
|
||||
Person p = new Person();
|
||||
p.setFullName(context.getStringAttribute("cn"));
|
||||
p.setLastName(context.getStringAttribute("sn"));
|
||||
p.setDescription(context.getStringAttribute("description"));
|
||||
return p;
|
||||
}
|
||||
}</emphasis>
|
||||
|
||||
public Person findByPrimaryKey(
|
||||
String name, String company, String country) {
|
||||
Name dn = buildDn(name, company, country);
|
||||
return ldapTemplate.lookup(dn, <emphasis role="bold">new PersonContextMapper()</emphasis>);
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>The above code shows that it is possible to retrieve the attributes
|
||||
directly by name, without having to go through the
|
||||
<literal>Attributes</literal> and <literal>BasicAttribute</literal>
|
||||
classes. This is particularly useful when working with multi-value attributes. Extracting values from
|
||||
multi-value attributes normally requires looping through a <literal>NamingEnumeration</literal> of
|
||||
attribute values returned from the <literal>Attributes</literal> implementation. The
|
||||
<literal>DirContextAdapter</literal> can do this for you, using the <literal>getStringAttributes()</literal>
|
||||
or <literal>getObjectAttributes()</literal> methods:</para>
|
||||
<example>
|
||||
<title>Getting multi-value attribute values using <literal>getStringAttributes()</literal></title>
|
||||
|
||||
<programlisting>private static class PersonContextMapper implements ContextMapper {
|
||||
public Object mapFromContext(Object ctx) {
|
||||
DirContextAdapter context = (DirContextAdapter)ctx;
|
||||
Person p = new Person();
|
||||
p.setFullName(context.getStringAttribute("cn"));
|
||||
p.setLastName(context.getStringAttribute("sn"));
|
||||
p.setDescription(context.getStringAttribute("description"));
|
||||
// The roleNames property of Person is an String array
|
||||
<emphasis role="bold">p.setRoleNames(context.getStringAttributes("roleNames"));</emphasis>
|
||||
return p;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<sect2>
|
||||
<title>The AbstractContextMapper</title>
|
||||
<para>Spring LDAP provides an abstract base implementation of <literal>ContextMapper</literal>,
|
||||
<literal>AbstractContextMapper</literal>. This automatically takes care of the casting of the supplied
|
||||
<literal>Object</literal> parameter to <literal>DirContexOperations</literal>.
|
||||
The <literal>PersonContextMapper</literal> above can thus be re-written as follows:
|
||||
</para>
|
||||
<example>
|
||||
<title>Using an AbstractContextMapper</title>
|
||||
|
||||
<programlisting>
|
||||
private static class PersonContextMapper <emphasis role="bold">extends AbstractContextMapper</emphasis> {
|
||||
public Object <emphasis role="bold">doMapFromContext</emphasis>(DirContextOperations ctx) {
|
||||
Person p = new Person();
|
||||
p.setFullName(context.getStringAttribute("cn"));
|
||||
p.setLastName(context.getStringAttribute("sn"));
|
||||
p.setDescription(context.getStringAttribute("description"));
|
||||
return p;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Binding and Modifying Using DirContextAdapter</title>
|
||||
|
||||
<para>While very useful when extracting attribute values, <literal>DirContextAdapter</literal> is even more
|
||||
powerful for hiding attribute details when binding and modifying data.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Binding</title>
|
||||
|
||||
<para>This is an example of an improved implementation of the create DAO
|
||||
method. Compare it with the previous implementation in <xref
|
||||
linkend="basic-binding-data" />.</para>
|
||||
|
||||
<example id="example-binding-contextmapper">
|
||||
<title>Binding using <literal>DirContextAdapter</literal></title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
...
|
||||
public void create(Person p) {
|
||||
Name dn = buildDn(p);
|
||||
DirContextAdapter context = new DirContextAdapter(dn);
|
||||
|
||||
<emphasis role="bold">context.setAttributeValues("objectclass", new String[] {"top", "person"});
|
||||
context.setAttributeValue("cn", p.getFullname());
|
||||
context.setAttributeValue("sn", p.getLastname());
|
||||
context.setAttributeValue("description", p.getDescription());</emphasis>
|
||||
|
||||
ldapTemplate.bind(dn, context, null);
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>Note that we use the <literal>DirContextAdapter</literal> instance
|
||||
as the second parameter to bind, which should be a <literal>Context</literal>.
|
||||
The third parameter is <literal>null</literal>, since we're not using any
|
||||
<literal>Attributes</literal>.</para>
|
||||
<para>Also note the use of the <literal>setAttributeValues()</literal> method when setting the
|
||||
<literal>objectclass</literal> attribute values. The <literal>objectclass</literal> attribute is
|
||||
multi-value, and similar to the troubles of extracting muti-value attribute data, building multi-value
|
||||
attributes is tedious and verbose work. Using the <literal>setAttributeValues()</literal> mehtod you can
|
||||
have <literal>DirContextAdapter</literal> handle that work for you.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Modifying</title>
|
||||
|
||||
<para>The code for a <literal>rebind</literal> would be pretty much
|
||||
identical to <xref linkend="example-binding-contextmapper" />, except
|
||||
that the method called would be <literal>rebind</literal>. As we saw in
|
||||
<xref linkend="modify-modifyAttributes"/> a more correct approach would be to
|
||||
build a <literal>ModificationItem</literal> array containing the actual
|
||||
modifications you want to do. This would require you to determine the actual
|
||||
modifications compared to the data present in the LDAP tree. Again, this
|
||||
is something that <literal>DirContextAdapter</literal> can help you with; the
|
||||
<literal>DirContextAdapter</literal> has the ability to keep track of
|
||||
its modified attributes. The following example takes advantage of this
|
||||
feature:</para>
|
||||
|
||||
<example>
|
||||
<title>Modifying using <literal>DirContextAdapter</literal></title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
...
|
||||
public void update(Person p) {
|
||||
Name dn = buildDn(p);
|
||||
<emphasis role="bold">DirContextOperations context = ldapTemplate.lookupContext(dn);</emphasis>
|
||||
|
||||
context.setAttributeValues("objectclass", new String[] {"top", "person"});
|
||||
context.setAttributeValue("cn", p.getFullname());
|
||||
context.setAttributeValue("sn", p.getLastname());
|
||||
context.setAttributeValue("description", p.getDescription());
|
||||
|
||||
<emphasis role="bold">ldapTemplate.modifyAttributes(context);</emphasis>
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
<para>When no mapper is passed to a <literal>ldapTemplate.lookup()</literal> operation,
|
||||
the result will be a <literal>DirContextAdapter</literal> instance.
|
||||
While the <literal>lookup</literal> method returns an <literal>Object</literal>, the convenience
|
||||
method <literal>lookupContext</literal> method automatically casts the return value to
|
||||
a <literal>DirContextOperations</literal> (the interface that <literal>DirContextAdapter</literal> implements.</para>
|
||||
<para>The observant reader will see that we have duplicated code in the
|
||||
<literal>create</literal> and <literal>update</literal> methods. This
|
||||
code maps from a domain object to a context. It can be extracted to a
|
||||
separate method:</para>
|
||||
|
||||
<example>
|
||||
<title>Binding and modifying using DirContextAdapter</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
|
||||
...
|
||||
public void create(Person p) {
|
||||
Name dn = buildDn(p);
|
||||
DirContextAdapter context = new DirContextAdapter(dn);
|
||||
mapToContext(p, context);
|
||||
ldapTemplate.bind(dn, context, null);
|
||||
}
|
||||
|
||||
public void update(Person p) {
|
||||
Name dn = buildDn(p);
|
||||
DirContextOperations context = ldapTemplate.lookupContext(dn);
|
||||
mapToContext(person, context);
|
||||
ldapTemplate.modifyAttributes(context);
|
||||
}
|
||||
|
||||
protected void mapToContext (Person p, DirContextOperations context) {
|
||||
context.setAttributeValues("objectclass", new String[] {"top", "person"});
|
||||
context.setAttributeValue("cn", p.getFullName());
|
||||
context.setAttributeValue("sn", p.getLastName());
|
||||
context.setAttributeValue("description", p.getDescription());
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>A Complete PersonDao Class</title>
|
||||
|
||||
<para>To illustrate the power of Spring LDAP, here is a complete Person
|
||||
DAO implementation for LDAP in just 68 lines:</para>
|
||||
|
||||
<example>
|
||||
<title>A complete PersonDao class</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attributes;
|
||||
|
||||
import org.springframework.ldap.core.AttributesMapper;
|
||||
import org.springframework.ldap.core.ContextMapper;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.support.DistinguishedName;
|
||||
import org.springframework.ldap.filter.EqualsFilter;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
|
||||
public void setLdapTemplate(LdapTemplate ldapTemplate) {
|
||||
this.ldapTemplate = ldapTemplate;
|
||||
}
|
||||
|
||||
public void create(Person person) {
|
||||
DirContextAdapter context = new DirContextAdapter();
|
||||
mapToContext(person, context);
|
||||
ldapTemplate.bind(buildDn(person), context, null);
|
||||
}
|
||||
|
||||
public void update(Person person) {
|
||||
Name dn = buildDn(person);
|
||||
DirContextOperations context = ldapTemplate.lookupContext(dn);
|
||||
mapToContext(person, context);
|
||||
ldapTemplate.modifyAttributes(context);
|
||||
}
|
||||
|
||||
public void delete(Person person) {
|
||||
ldapTemplate.unbind(buildDn(person));
|
||||
}
|
||||
|
||||
public Person findByPrimaryKey(String name, String company, String country) {
|
||||
Name dn = buildDn(name, company, country);
|
||||
return (Person) ldapTemplate.lookup(dn, getContextMapper());
|
||||
}
|
||||
|
||||
public List findAll() {
|
||||
EqualsFilter filter = new EqualsFilter("objectclass", "person");
|
||||
return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper());
|
||||
}
|
||||
|
||||
protected ContextMapper getContextMapper() {
|
||||
return new PersonContextMapper();
|
||||
}
|
||||
|
||||
protected Name buildDn(Person person) {
|
||||
return buildDn(person.getFullname(), person.getCompany(), person.getCountry());
|
||||
}
|
||||
|
||||
protected Name buildDn(String fullname, String company, String country) {
|
||||
DistinguishedName dn = new DistinguishedName();
|
||||
dn.add("c", country);
|
||||
dn.add("ou", company);
|
||||
dn.add("cn", fullname);
|
||||
return dn;
|
||||
}
|
||||
|
||||
protected void mapToContext(Person person, DirContextOperations context) {
|
||||
context.setAttributeValues("objectclass", new String[] {"top", "person"});
|
||||
context.setAttributeValue("cn", person.getFullName());
|
||||
context.setAttributeValue("sn", person.getLastName());
|
||||
context.setAttributeValue("description", person.getDescription());
|
||||
}
|
||||
|
||||
private static class PersonContextMapper extends AbstractContextMapper {
|
||||
public Object doMapFromContext(DirContextOperations context) {
|
||||
Person person = new Person();
|
||||
person.setFullName(context.getStringAttribute("cn"));
|
||||
person.setLastName(context.getStringAttribute("sn"));
|
||||
person.setDescription(context.getStringAttribute("description"));
|
||||
return person;
|
||||
}
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<note>
|
||||
<para>In several cases the Distinguished Name (DN) of an object is
|
||||
constructed using properties of the object. E.g. in the above example,
|
||||
the country, company and full name of the <literal>Person</literal> are
|
||||
used in the DN, which means that updating any of these properties will
|
||||
actually require moving the entry in the LDAP tree using the
|
||||
<literal>rename()</literal> operation in addition to updating the
|
||||
<literal>Attribute</literal> values. Since this is highly implementation
|
||||
specific this is something you'll need to keep track of yourself -
|
||||
either by disallowing the user to change these properties or performing
|
||||
the <literal>rename()</literal> operation in your
|
||||
<literal>update()</literal> method if needed.</para>
|
||||
</note>
|
||||
</sect1>
|
||||
</chapter>
|
||||
148
core/docs/reference/src/executors.xml
Normal file
@@ -0,0 +1,148 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="executors">
|
||||
<title>Adding Missing Overloaded API Methods</title>
|
||||
|
||||
<sect1 id="executors-search">
|
||||
<title>Implementing Custom Search Methods</title>
|
||||
|
||||
<para>While <literal>LdapTemplate</literal> contains several overloaded
|
||||
versions of the most common operations in <literal>DirContext</literal>,
|
||||
we have not provided an alternative for each and every method signature,
|
||||
mostly because there are so many of them. We have, however, provided a
|
||||
means to call whichever <literal>DirContext</literal> method you want
|
||||
and still get the benefits that LdapTemplate provides.</para>
|
||||
|
||||
<para>Let's say that you want to call the following <literal>DirContext</literal>
|
||||
method:</para>
|
||||
|
||||
<programlisting>NamingEnumeration search(Name name, String filterExpr, Object[] filterArgs, SearchControls ctls)</programlisting>
|
||||
|
||||
<para>There is no corresponding overloaded method in LdapTemplate. The way to solve
|
||||
this is to use a custom <literal>SearchExecutor</literal> implementation:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>public interface SearchExecutor {
|
||||
public NamingEnumeration executeSearch(DirContext ctx) throws NamingException;
|
||||
}</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>In your custom executor, you have access to a <literal>DirContext</literal>
|
||||
object, which you use to call the method you want. You then provide a handler
|
||||
that is responsible for mapping attributes and collecting the results. You can
|
||||
for example use one of the available implementations of
|
||||
<literal>CollectingNameClassPairCallbackHandler</literal>, which will collect
|
||||
the mapped results in an internal list. In order to
|
||||
actually execute the search, you call the <literal>search</literal>
|
||||
method in LdapTemplate that takes an executor and a handler as arguments. Finally,
|
||||
you return whatever your handler has collected.</para>
|
||||
|
||||
<example>
|
||||
<title>A custom search method using SearchExecutor and
|
||||
AttributesMapper</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
...
|
||||
public List search(final Name base, final String filter, final String[] params,
|
||||
final SearchControls ctls) {
|
||||
<emphasis role="bold">SearchExecutor executor = new SearchExecutor() {
|
||||
public NamingEnumeration executeSearch(DirContext ctx) {
|
||||
return ctx.search(base, filter, params, ctls);
|
||||
}
|
||||
}</emphasis>;
|
||||
|
||||
CollectingNameClassPairCallbackHandler handler =
|
||||
new AttributesMapperCallbackHandler(new PersonAttributesMapper());
|
||||
|
||||
ldapTemplate.search(<emphasis role="bold">executor</emphasis>, handler);
|
||||
return handler.getList();
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>If you prefer the <literal>ContextMapper</literal> to the
|
||||
<literal>AttributesMapper</literal>, this is what it would look
|
||||
like:</para>
|
||||
|
||||
<example>
|
||||
<title>A custom search method using SearchExecutor and
|
||||
ContextMapper</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
...
|
||||
public List search(final Name base, final String filter, final String[] params,
|
||||
final SearchControls ctls) {
|
||||
SearchExecutor executor = new SearchExecutor() {
|
||||
public NamingEnumeration executeSearch(DirContext ctx) {
|
||||
return ctx.search(base, filter, params, ctls);
|
||||
}
|
||||
};
|
||||
|
||||
CollectingNameClassPairCallbackHandler handler =
|
||||
<emphasis role="bold">new ContextMapperCallbackHandler(new PersonContextMapper())</emphasis>;
|
||||
|
||||
ldapTemplate.search(executor, handler);
|
||||
return handler.getList();
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<note>
|
||||
<para>When using the
|
||||
<literal>ContextMapperCallbackHandler</literal> you must
|
||||
make sure that you have called
|
||||
<literal>setReturningObjFlag(true)</literal> on your
|
||||
<literal>SearchControls</literal> instance.</para>
|
||||
</note>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="executors-others">
|
||||
<title>Implementing Other Custom Context Methods</title>
|
||||
|
||||
<para>In the same manner as for custom <literal>search</literal> methods,
|
||||
you can actually execute any method in <literal>DirContext</literal> by
|
||||
using a <literal>ContextExecutor</literal>.</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>public interface ContextExecutor {
|
||||
public Object executeWithContext(DirContext ctx) throws NamingException;
|
||||
}</programlisting>
|
||||
|
||||
<para>When implementing a custom <literal>ContextExecutor</literal>, you
|
||||
can choose between using the <literal>executeReadOnly()</literal> or the
|
||||
<literal>executeReadWrite()</literal> method. Let's say that we want to
|
||||
call this method:</para>
|
||||
</informalexample>
|
||||
|
||||
<programlisting>Object lookupLink(Name name)</programlisting>
|
||||
|
||||
<para>It's available in <literal>DirContext</literal>, but there is no
|
||||
matching method in <literal>LdapTemplate</literal>. It's a lookup method,
|
||||
so it should be read-only. We can implement it like this:</para>
|
||||
|
||||
<example>
|
||||
<title>A custom DirContext method using ContextExecutor</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
...
|
||||
public Object lookupLink(final Name name) {
|
||||
ContextExecutor executor = new ContextExecutor() {
|
||||
public Object executeWithContext(DirContext ctx) {
|
||||
return ctx.lookupLink(name);
|
||||
}
|
||||
};
|
||||
|
||||
return ldapTemplate.executeReadOnly(executor);
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>In the same manner you can execute a read-write operation using
|
||||
the <literal>executeReadWrite()</literal> method.</para>
|
||||
</example>
|
||||
</sect1>
|
||||
</chapter>
|
||||
BIN
core/docs/reference/src/images/NamingException.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
core/docs/reference/src/images/banner4.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
core/docs/reference/src/images/bannerR.gif
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
core/docs/reference/src/images/logo.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
core/docs/reference/src/images/package-dependencies.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
core/docs/reference/src/images/package-structure.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
64
core/docs/reference/src/index.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version='1.0' encoding="iso-8859-1"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"../lib/docbook-dtd/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY preface SYSTEM "preface.xml">
|
||||
<!ENTITY overview SYSTEM "overview.xml">
|
||||
<!ENTITY basic SYSTEM "basic.xml">
|
||||
<!ENTITY dirobjectfactory SYSTEM "dirobjectfactory.xml">
|
||||
<!ENTITY executors SYSTEM "executors.xml">
|
||||
<!ENTITY contextprocessor SYSTEM "contextprocessor.xml">
|
||||
<!ENTITY transactions SYSTEM "transactions.xml">
|
||||
<!ENTITY simple SYSTEM "simple.xml">
|
||||
<!ENTITY configuration SYSTEM "configuration.xml">
|
||||
<!ENTITY pooling SYSTEM "pooling.xml">
|
||||
]>
|
||||
|
||||
|
||||
<book>
|
||||
|
||||
<bookinfo>
|
||||
<title>Spring LDAP</title>
|
||||
<subtitle>Reference Documentation</subtitle>
|
||||
<releaseinfo>Version 1.2.1</releaseinfo>
|
||||
<pubdate>December 2007</pubdate>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Mattias</firstname>
|
||||
<surname>Arthursson</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Ulrik</firstname>
|
||||
<surname>Sandberg</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Eric</firstname>
|
||||
<surname>Dalquist</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<legalnotice>
|
||||
<para>
|
||||
Copies of this document may be made for your own use and
|
||||
for distribution to others, provided that you do not
|
||||
charge any fee for such copies and further provided that
|
||||
each copy contains this Copyright Notice, whether
|
||||
distributed in print or electronically.
|
||||
</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<toc />
|
||||
|
||||
&preface;
|
||||
&overview;
|
||||
&basic;
|
||||
&dirobjectfactory;
|
||||
&transactions;
|
||||
&executors;
|
||||
&contextprocessor;
|
||||
&simple;
|
||||
&configuration;
|
||||
&pooling;
|
||||
|
||||
</book>
|
||||
417
core/docs/reference/src/overview.xml
Normal file
@@ -0,0 +1,417 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<sect1 id="introduction-overview">
|
||||
<title>Overview</title>
|
||||
|
||||
<para>Spring-LDAP (<ulink
|
||||
url="http://www.springframework.org/ldap">http://www.springframework.org/ldap</ulink>)
|
||||
is a library for simpler LDAP programming in Java, built on the same
|
||||
principles as the <ulink
|
||||
url="http://static.springframework.org/spring/docs/current/api/org/springframework/jdbc/core/JdbcTemplate.html">JdbcTemplate</ulink>
|
||||
in Spring JDBC. It completely eliminates the need to worry about creating
|
||||
and closing <literal>LdapContext</literal> and looping through
|
||||
<literal>NamingEnumeration</literal>. It also provides a more
|
||||
comprehensive unchecked Exception hierarchy, built on Spring's
|
||||
<literal>DataAccessException</literal>. As a bonus, it also contains
|
||||
classes for dynamically building LDAP filters and DNs (Distinguished
|
||||
Names), LDAP attribute management, and client-side LDAP transaction management.</para>
|
||||
|
||||
<para>Consider, for example, a method that should search some storage for
|
||||
all persons and return their names in a list. Using JDBC, we would create
|
||||
a <emphasis>connection</emphasis> and execute a <emphasis>query</emphasis>
|
||||
using a <emphasis>statement</emphasis>. We would then loop over the
|
||||
<emphasis>result set</emphasis> and retrieve the
|
||||
<emphasis>column</emphasis> we want, adding it to a list. In contrast,
|
||||
using Java LDAP, we would create a <emphasis>context</emphasis> and
|
||||
perform a <emphasis>search</emphasis> using a <emphasis>search
|
||||
filter</emphasis>. We would then loop over the resulting <emphasis>naming
|
||||
enumeration</emphasis> and retrieve the <emphasis>attribute</emphasis> we
|
||||
want, adding it to a list.</para>
|
||||
|
||||
<para>The traditional way of implementing this person name search method
|
||||
in Java LDAP looks like this, where the code marked as bold actually
|
||||
performs tasks related to the business purpose of the method:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class TraditionalPersonDaoImpl implements PersonDao {
|
||||
public List getAllPersonNames() {
|
||||
Hashtable env = new Hashtable();
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.PROVIDER_URL, "ldap://localhost:389/dc=example,dc=com");
|
||||
|
||||
DirContext ctx;
|
||||
try {
|
||||
ctx = new InitialDirContext(env);
|
||||
} catch (NamingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
LinkedList list = new LinkedList();
|
||||
NamingEnumeration results = null;
|
||||
try {
|
||||
SearchControls controls = new SearchControls();
|
||||
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||
results = ctx.<emphasis role="bold">search("", "(objectclass=person)"</emphasis>, controls);
|
||||
|
||||
while (results.hasMore()) {
|
||||
SearchResult searchResult = (SearchResult) results.next();
|
||||
Attributes attributes = searchResult.getAttributes();
|
||||
<emphasis role="bold">Attribute attr = attributes.get("cn");
|
||||
String cn = (String) attr.get();
|
||||
list.add(cn);</emphasis>
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
// The base context was not found.
|
||||
// Just clean up and exit.
|
||||
} catch (NamingException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (results != null) {
|
||||
try {
|
||||
results.close();
|
||||
} catch (Exception e) {
|
||||
// Never mind this.
|
||||
}
|
||||
}
|
||||
if (ctx != null) {
|
||||
try {
|
||||
ctx.close();
|
||||
} catch (Exception e) {
|
||||
// Never mind this.
|
||||
}
|
||||
}
|
||||
}
|
||||
<emphasis role="bold">return list;</emphasis>
|
||||
}
|
||||
}</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>By using the Spring LDAP classes <literal>AttributesMapper</literal>
|
||||
and <literal>LdapTemplate</literal>, we get the exact same functionality
|
||||
with the following code:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting>package com.example.dao;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
|
||||
public void setLdapTemplate(LdapTemplate ldapTemplate) {
|
||||
this.ldapTemplate = ldapTemplate;
|
||||
}
|
||||
|
||||
public List getAllPersonNames() {
|
||||
return ldapTemplate.<emphasis role="bold">search(
|
||||
"", "(objectclass=person)"</emphasis>,
|
||||
new AttributesMapper() {
|
||||
public Object mapFromAttributes(Attributes attrs)
|
||||
throws NamingException {
|
||||
<emphasis role="bold">return attrs.get("cn").get();</emphasis>
|
||||
}
|
||||
});
|
||||
}
|
||||
}</programlisting>
|
||||
</informalexample>
|
||||
|
||||
<para>The amount of boiler-plate code is significantly less than in the
|
||||
traditional example. The <literal>LdapTemplate</literal> version of the
|
||||
search method performs the search, maps the attributes to a string using
|
||||
the given <literal>AttributesMapper</literal>, collects the strings in an
|
||||
internal list, and finally returns the list.</para>
|
||||
|
||||
<para>Note that the <literal>PersonDaoImpl</literal> code simply assumes
|
||||
that it has an <literal>LdapTemplate</literal> instance, rather than
|
||||
looking one up somewhere. It provides a set method for this purpose. There
|
||||
is nothing Spring-specific about this "Inversion of Control". Anyone that
|
||||
can create an instance of <literal>PersonDaoImpl</literal> can also set
|
||||
the <literal>LdapTemplate</literal> on it. However, Spring provides a very
|
||||
flexible and easy way of <ulink
|
||||
url="http://static.springframework.org/spring/docs/current/reference/beans.html">achieving
|
||||
this</ulink>. The Spring container can be told to wire up an instance of
|
||||
<literal>LdapTemplate</literal> with its required dependencies and inject
|
||||
it into the <literal>PersonDao</literal> instance. This wiring can be
|
||||
defined in various ways, but the most common is through XML:</para>
|
||||
|
||||
<informalexample>
|
||||
<programlisting><beans>
|
||||
<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
|
||||
<property name="url" value="ldap://localhost:389" />
|
||||
<property name="base" value="dc=example,dc=com" />
|
||||
<property name="userDn" value="cn=Manager" />
|
||||
<property name="password" value="secret" />
|
||||
</bean>
|
||||
|
||||
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
|
||||
<constructor-arg ref="contextSource" />
|
||||
</bean>
|
||||
|
||||
<bean id="personDao" class="com.example.dao.PersonDaoImpl">
|
||||
<property name="ldapTemplate" ref="ldapTemplate" />
|
||||
</bean>
|
||||
</beans></programlisting>
|
||||
</informalexample>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="introduction-packaging">
|
||||
<title>Packaging overview</title>
|
||||
|
||||
<para>At a minimum, to use Spring LDAP you need:</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><emphasis>spring-ldap</emphasis> (the Spring LDAP library)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis>spring-core</emphasis> (miscellaneous utility classes used internally by
|
||||
the framework)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis>spring-beans</emphasis> (contains interfaces and classes for manipulating
|
||||
Java beans)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis>commons-logging</emphasis> (a simple logging facade, used
|
||||
internally)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis>commons-lang</emphasis> (misc utilities, used internally)</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
<para>In addition to the required dependencies the following optional dependencies
|
||||
are required for certain functionality:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis>acegi-security</emphasis> (For Acegi security integration using <literal>AcegiAuthenticationSource</literal>)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>spring-context</emphasis> (If your application is wired up using the Spring Application Context -
|
||||
adds the ability for application objects to obtain resources using a consistent API. Definitely needed if you are
|
||||
planning on using the BaseLdapPathBeanPostProcessor.)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>spring-dao</emphasis> (If you are planning to use the client side compensating transaction support)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>spring-jdbc</emphasis> (If you are planning to use the client side compensating transaction support)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>ldapbp</emphasis> (Sun LDAP Booster Pack - if you will use the LDAP v3 Server controls integration)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>commons-pool</emphasis> (If you are planning to use the pooling functionality)</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="introduction-package-structure">
|
||||
<title>Package structure</title>
|
||||
|
||||
<para>This section provides an overview of the logical package structure
|
||||
of the Spring LDAP codebase. The dependencies for each package are clearly
|
||||
noted. A package dependency noted as <emphasis>(optional)</emphasis> means
|
||||
that the dependency is needed to compile the package but is optionally
|
||||
needed at runtime (depending on your use of the package). For example, use
|
||||
of Spring LDAP together with Acegi Security entails use of the
|
||||
<literal>org.acegisecurity</literal> package.</para>
|
||||
|
||||
<figure>
|
||||
<title>Spring LDAP package structure</title>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="images/package-dependencies.png" format="png" />
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</figure>
|
||||
|
||||
<sect2 id="transaction.compensating">
|
||||
<title>org.springframework.transaction.compensating</title>
|
||||
|
||||
<para>The <emphasis>transaction.compensating</emphasis> package contains
|
||||
the generic compensating transaction support. This is not LDAP-specific
|
||||
or JNDI-specific in any way.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap">
|
||||
<title>org.springframework.ldap</title>
|
||||
|
||||
<para>The <emphasis>ldap</emphasis> package contains the exceptions of
|
||||
the library. These exceptions form an unchecked hierarchy that mirrors
|
||||
the NamingException hierarchy.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: spring-core</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.core">
|
||||
<title>org.springframework.ldap.core</title>
|
||||
|
||||
<para>The <emphasis>ldap.core</emphasis> package contains the central
|
||||
abstractions of the library. These abstractions include
|
||||
AuthenticationSource, ContextSource, DirContextProcessor, and
|
||||
NameClassPairCallbackHandler. This package also contains the central
|
||||
class LdapTemplate, plus various mappers and executors.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, ldap.support, spring-beans,
|
||||
commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.core.support">
|
||||
<title>org.springframework.ldap.core.support</title>
|
||||
|
||||
<para>The <emphasis>ldap.core.support</emphasis> package contains
|
||||
supporting implementations of some of the core interfaces.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, ldap.support, spring-core,
|
||||
spring-beans, spring-context (optional), commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.support">
|
||||
<title>org.springframework.ldap.support</title>
|
||||
|
||||
<para>The <emphasis>ldap.support</emphasis> package contains supporting
|
||||
utilities, like the exception translation mechanism.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, spring-core, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.authentication">
|
||||
<title>org.springframework.ldap.authentication</title>
|
||||
|
||||
<para>The <emphasis>ldap.authentication</emphasis> package contains an
|
||||
implementation of the AuthenticationSource interface that can be used
|
||||
with <ulink url="http://www.acegisecurity.org/">Acegi Security</ulink>,
|
||||
as well as related helper classes.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, acegi-security (optional),
|
||||
spring-beans, commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.control">
|
||||
<title>org.springframework.ldap.control</title>
|
||||
|
||||
<para>The <emphasis>ldap.control</emphasis> package contains an abstract
|
||||
implementation of the DirContextProcessor interface that can be used as
|
||||
a basis for processing RequestControls and ResponseControls. There is
|
||||
also a concrete implementation that handles paged search results. The
|
||||
<ulink url="http://java.sun.com/products/jndi/">LDAP Booster
|
||||
Pack</ulink> is used to get support for controls.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, ldap.core, LDAP booster pack (optional), spring-core,
|
||||
commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.filter">
|
||||
<title>org.springframework.ldap.filter</title>
|
||||
|
||||
<para>The <emphasis>ldap.filter</emphasis> package contains the Filter
|
||||
abstraction and several implementations of it.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, commons-lang</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.transaction.compensating">
|
||||
<title>org.springframework.ldap.transaction.compensating</title>
|
||||
|
||||
<para>The <emphasis>ldap.transaction.compensating</emphasis> package contains the
|
||||
core LDAP-specific implementation of compensating transactions.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, ldap.core, transaction.compensating,
|
||||
spring-core, commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.transaction.compensating.manager">
|
||||
<title>org.springframework.ldap.transaction.compensating.manager</title>
|
||||
|
||||
<para>The <emphasis>ldap.transaction.compensating.manager</emphasis> package contains the
|
||||
core implementation classes for client-side compensating transactions.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, ldap.core, ldap.transaction.compensating,
|
||||
ldap.transaction.compensating.support, transaction.compensating,
|
||||
spring-dao (optional), spring-jdbc (optional), commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.transaction.compensating.support">
|
||||
<title>org.springframework.ldap.transaction.compensating.support</title>
|
||||
|
||||
<para>The <emphasis>ldap.transaction.compensating.support</emphasis> package contains
|
||||
useful helper classes for client-side compensating transactions.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, ldap.transaction.compensating</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<para>For the exact list of jar dependencies, see the Spring LDAP <ulink
|
||||
url="http://jayasoft.org/ivy">Ivy</ulink> dependency manager descriptor
|
||||
located within the Spring LDAP distribution at
|
||||
<literal>spring-ldap/ivy.xml</literal></para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="introduction-support">
|
||||
<title>Support</title>
|
||||
|
||||
<para>Spring LDAP 1.2.1 is supported on Spring 1.2.8 or later, including
|
||||
2.0.x.</para>
|
||||
|
||||
<para>The community support forum is located at <ulink
|
||||
url="http://forum.springframework.org">http://forum.springframework.org</ulink>,
|
||||
and the project web page is <ulink
|
||||
url="http://www.springframework.org/ldap">http://www.springframework.org/ldap</ulink>.</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
550
core/docs/reference/src/pooling.xml
Normal file
@@ -0,0 +1,550 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<chapter id="pooling">
|
||||
<title>Pooling Support</title>
|
||||
|
||||
<sect1 id="pooling-intro">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>
|
||||
Pooling LDAP connections helps mitigate the overhead of
|
||||
creating a new LDAP connection for each LDAP interaction.
|
||||
While
|
||||
<ulink
|
||||
url="http://java.sun.com/products/jndi/tutorial/ldap/connect/pool.html">
|
||||
Java LDAP pooling support
|
||||
</ulink>
|
||||
exists it is limited in its configuration options and
|
||||
features, such as connection validation and pool
|
||||
maintenance. Spring LDAP provides support for detailed pool
|
||||
configuration on a per-
|
||||
<literal>ContextSource</literal>
|
||||
basis.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Pooling support is provided by
|
||||
<literal>PoolingContextSource</literal>
|
||||
which can wrap any
|
||||
<literal>ContextSource</literal>
|
||||
and pool both read-only and read-write
|
||||
<literal>DirContext</literal>
|
||||
objects.
|
||||
<ulink url="http://commons.apache.org/pool/index.html">
|
||||
Jakarta Commons-Pool
|
||||
</ulink>
|
||||
is used to provide the underlying pool implementation.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="pooling-validation">
|
||||
<title>DirContext Validation</title>
|
||||
|
||||
<para>
|
||||
Validation of pooled connections is the primary motivation
|
||||
for using a custom pooling library versus the JDK provided
|
||||
LDAP pooling functionality. Validation allows pooled
|
||||
<literal>DirContext</literal>
|
||||
connections to be checked to ensure they are still properly
|
||||
connected and configured when checking them out of the pool,
|
||||
in to the pool or while idle in the pool
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The
|
||||
<literal>DirContextValidator</literal>
|
||||
interface is used by the
|
||||
<literal>PoolingContextSource</literal>
|
||||
for validation and
|
||||
<literal>DefaultDirContextValidator</literal>
|
||||
is provided as the default validation implementation.
|
||||
<literal>DefaultDirContextValidator</literal>
|
||||
does a
|
||||
<literal>
|
||||
DirContext.search(String, String, SearchControls)
|
||||
</literal>
|
||||
, with an empty name, a filter of
|
||||
<literal>"objectclass=*"</literal>
|
||||
and
|
||||
<literal>SearchControls</literal>
|
||||
set to limit a single result with the only the objectclass
|
||||
attribute and a 500ms timeout. If the returned
|
||||
<literal>NamingEnumeration</literal>
|
||||
has results the
|
||||
<literal>DirContext</literal>
|
||||
passes validation, if no results are returned or an
|
||||
exception is thrown the
|
||||
<literal>DirContext</literal>
|
||||
fails validation. The
|
||||
<literal>DefaultDirContextValidator</literal>
|
||||
should work with no configuration changes on most LDAP
|
||||
servers and provide the fastest way to validate the
|
||||
<literal>DirContext</literal>
|
||||
.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="pooling-properties">
|
||||
<title>Pool Properties</title>
|
||||
|
||||
<para>
|
||||
The following properties are available on the
|
||||
<literal>PoolingContextSource</literal>
|
||||
for configuration of the DirContext pool. The
|
||||
<literal>contextSource</literal>
|
||||
property must be set and the
|
||||
<literal>dirContextValidator</literal>
|
||||
property must be set if validation is enabled, all other
|
||||
properties are optional.
|
||||
</para>
|
||||
|
||||
<table frame="all">
|
||||
<title>Pooling Configuration Properties</title>
|
||||
<tgroup align="left" cols="3" colsep="1" rowsep="1">
|
||||
<colspec colname="c1" />
|
||||
|
||||
<colspec colname="c2" />
|
||||
|
||||
<colspec colname="c3" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Parameter</entry>
|
||||
|
||||
<entry>Default</entry>
|
||||
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<literal>contextSource</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>null</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The
|
||||
<literal>ContextSource</literal>
|
||||
implementation to get
|
||||
<literal>DirContext</literal>
|
||||
s from to populate the pool.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>dirContextValidator</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>null</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The
|
||||
<literal>DirContextValidator</literal>
|
||||
implementation to use when validating
|
||||
connections. This is required if
|
||||
<literal>testOnBorrow</literal>
|
||||
,
|
||||
<literal>testOnReturn</literal>
|
||||
, or
|
||||
<literal>testWhileIdle</literal>
|
||||
options are set to
|
||||
<literal>true</literal>
|
||||
.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>maxActive</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>8</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The maximum number of active connections of
|
||||
each type (read-only|read-write) that can be
|
||||
allocated from this pool at the same time,
|
||||
or non-positive for no limit.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>maxTotal</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>-1</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The overall maximum number of active
|
||||
connections (for all types) that can be
|
||||
allocated from this pool at the same time,
|
||||
or non-positive for no limit.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>maxIdle</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>8</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The maximum number of active connections of
|
||||
each type (read-only|read-write) that can
|
||||
remain idle in the pool, without extra ones
|
||||
being released, or non-positive for no
|
||||
limit.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>minIdle</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>0</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The minimum number of active connections of
|
||||
each type (read-only|read-write) that can
|
||||
remain idle in the pool, without extra ones
|
||||
being created, or zero to create none.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>maxWait</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>-1</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The maximum number of milliseconds that the
|
||||
pool will wait (when there are no available
|
||||
connections) for a connection to be returned
|
||||
before throwing an exception, or
|
||||
non-positive to wait indefinitely.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>whenExhaustedAction</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>1</literal> (BLOCK)
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
Specifies the behaviour when the pool is
|
||||
exhausted.
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The
|
||||
FAIL (<literal>0</literal>)
|
||||
option will throw a
|
||||
<literal>
|
||||
NoSuchElementException
|
||||
</literal>
|
||||
when the pool is exhausted.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The
|
||||
BLOCK (<literal>1</literal>)
|
||||
option will wait until a new
|
||||
object is available. If
|
||||
<literal>maxWait</literal>
|
||||
is positive a
|
||||
<literal>
|
||||
NoSuchElementException
|
||||
</literal>
|
||||
is thrown if no new object is
|
||||
available after the
|
||||
<literal>maxWait</literal>
|
||||
time expires.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The
|
||||
GROW (<literal>2</literal>)
|
||||
option will create and return a
|
||||
new object (essentially making
|
||||
<literal>maxActive</literal>
|
||||
meaningless).
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>testOnBorrow</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>false</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The indication of whether objects will be
|
||||
validated before being borrowed from the
|
||||
pool. If the object fails to validate, it
|
||||
will be dropped from the pool, and an
|
||||
attempt to borrow another will be made.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>testOnReturn</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>false</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The indication of whether objects will be
|
||||
validated before being returned to the pool.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>testWhileIdle</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>false</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The indication of whether objects will be
|
||||
validated by the idle object evictor (if
|
||||
any). If an object fails to validate, it
|
||||
will be dropped from the pool.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>
|
||||
timeBetweenEvictionRunsMillis
|
||||
</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>-1</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The number of milliseconds to sleep between
|
||||
runs of the idle object evictor thread. When
|
||||
non-positive, no idle object evictor thread
|
||||
will be run.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>numTestsPerEvictionRun</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>3</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The number of objects to examine during each
|
||||
run of the idle object evictor thread (if
|
||||
any).
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>
|
||||
minEvictableIdleTimeMillis
|
||||
</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<literal>1000 * 60 * 30</literal>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
The minimum amount of time an object may sit
|
||||
idle in the pool before it is eligible for
|
||||
eviction by the idle object evictor (if
|
||||
any).
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="pooling-configuration">
|
||||
<title>Configuration</title>
|
||||
|
||||
<para>
|
||||
Configuring pooling should look very familiar if you're used
|
||||
to Jakarta Commons-Pool or Commons-DBCP. You will first
|
||||
create a normal
|
||||
<literal>ContextSource</literal>
|
||||
then wrap it in a
|
||||
<literal>PoolingContextSource</literal>
|
||||
.
|
||||
<informalexample>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
...
|
||||
<bean id="contextSource" class="org.springframework.ldap.pool.factory.PoolingContextSource">
|
||||
<property name="contextSource" ref="contextSourceTarget" />
|
||||
</bean>
|
||||
|
||||
<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
|
||||
<property name="url" value="ldap://localhost:389" />
|
||||
<property name="base" value="dc=example,dc=com" />
|
||||
<property name="userDn" value="cn=Manager" />
|
||||
<property name="password" value="secret" />
|
||||
<property name="pooled" value="false"/>
|
||||
</bean>
|
||||
...
|
||||
</beans>
|
||||
]]></programlisting>
|
||||
</informalexample>
|
||||
In a real world example you would probably configure the
|
||||
pool options and enable connection validation; the above
|
||||
serves as an example to demonstrate the general idea.
|
||||
<note>
|
||||
<para>
|
||||
Ensure that the
|
||||
<literal>pooled</literal>
|
||||
property is set to
|
||||
<literal>false</literal>
|
||||
on any
|
||||
<literal>ContextSource</literal>
|
||||
that will be wrapped in a
|
||||
<literal>PoolingContextSource</literal>
|
||||
. The
|
||||
<literal>PoolingContextSource</literal>
|
||||
must be able to create new connections when needed
|
||||
and if
|
||||
<literal>pooled</literal>
|
||||
is set to
|
||||
<literal>true</literal>
|
||||
that may not be possible.
|
||||
</para>
|
||||
</note>
|
||||
<note>
|
||||
<para>
|
||||
You'll notice that the actual
|
||||
<literal>ContextSource</literal>
|
||||
gets an id with a "Target" suffix. The bean you will
|
||||
actually refer to is the
|
||||
<literal>PoolingContextSource</literal>
|
||||
that wraps the target
|
||||
<literal>contextSource</literal>
|
||||
</para>
|
||||
</note>
|
||||
</para>
|
||||
|
||||
<sect2 id="pooling-advanced-configuration">
|
||||
<title>Validation Configuration</title>
|
||||
|
||||
<para>
|
||||
Adding validation and a few pool configuration tweaks to
|
||||
the above example is straight forward. Inject a
|
||||
<literal>DirContextValidator</literal>
|
||||
and set when validation should occur and the pool is
|
||||
ready to go.
|
||||
<informalexample>
|
||||
<programlisting><![CDATA[
|
||||
<beans>
|
||||
...
|
||||
<bean id="contextSource" class="org.springframework.ldap.pool.factory.PoolingContextSource">
|
||||
<property name="contextSource" ref="contextSourceTarget" />
|
||||
<property name="dirContextValidator" ref="dirContextValidator" />
|
||||
<property name="testOnBorrow" value="true" />
|
||||
<property name="testWhileIdle" value="true" />
|
||||
</bean>
|
||||
|
||||
<bean id="dirContextValidator"
|
||||
class="org.springframework.ldap.pool.validation.DefaultDirContextValidator" />
|
||||
|
||||
<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
|
||||
<property name="url" value="ldap://localhost:389" />
|
||||
<property name="base" value="dc=example,dc=com" />
|
||||
<property name="userDn" value="cn=Manager" />
|
||||
<property name="password" value="secret" />
|
||||
<property name="pooled" value="false"/>
|
||||
</bean>
|
||||
...
|
||||
</beans>
|
||||
]]></programlisting>
|
||||
</informalexample>
|
||||
The above example will test each
|
||||
<literal>DirContext</literal>
|
||||
before it is passed to the client application and test
|
||||
<literal>DirContext</literal>
|
||||
s that have been sitting idle in the pool.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="pooling-issues">
|
||||
<title>Known Issues</title>
|
||||
|
||||
<sect2 id="pooling-custom-auth-issue">
|
||||
<title>Custom Authentication</title>
|
||||
|
||||
<para>
|
||||
The <literal>PoolingContextSource</literal> assumes that all
|
||||
<literal>DirContext</literal> objects retrieved from
|
||||
<literal>ContextSource.getReadOnlyContext()</literal> will have
|
||||
the same environment and likewise that all
|
||||
<literal>DirContext</literal> objects retrieved from
|
||||
<literal>ContextSource.getReadWriteContext()</literal> will
|
||||
have the same environment. This means that wrapping a
|
||||
<literal>LdapContextSource</literal> configured with an
|
||||
<literal>AuthenticationSource</literal> in a
|
||||
<literal>PoolingContextSource</literal> will not function
|
||||
as expected. The pool would be populated using the credentials
|
||||
of the first user and unless new connections were needed
|
||||
subsequent context requests would not be filled for the user
|
||||
specified by the <literal>AuthenticationSource</literal> for
|
||||
the requesting thread.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
32
core/docs/reference/src/preface.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<preface id="preface">
|
||||
<title>Preface</title>
|
||||
<para>
|
||||
The Java Naming and Directory Interface (JNDI) is for LDAP programming
|
||||
what Java Database Connectivity (JDBC) is for SQL programming. There are
|
||||
several similarities between JDBC and JNDI/LDAP (Java LDAP). Despite
|
||||
being two completely different APIs with different pros and cons, they
|
||||
share a number of less flattering characteristics:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>They require extensive plumbing code, even to perform the simplest of tasks.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>All resources need to be correctly closed, no matter what happens.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Exception handling is difficult.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The above points often lead to massive code duplication in common usages
|
||||
of the APIs. As we all know, code duplication is one of the worst code smells.
|
||||
All in all, it boils down to this: JDBC and LDAP programming in Java are both
|
||||
incredibly dull and repetitive.
|
||||
</para>
|
||||
<para>
|
||||
Spring JDBC, a part of the Spring framework, provides excellent utilities for
|
||||
simplifying SQL programming. We need a similar framework for Java LDAP programming.
|
||||
</para>
|
||||
</preface>
|
||||
35
core/docs/reference/src/simple.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<chapter id="simple">
|
||||
<title>Java 5 Support</title>
|
||||
|
||||
<sect1 id="simple-ldap-template">
|
||||
<title>SimpleLdapTemplate</title>
|
||||
|
||||
<para>As of version 1.3 Spring LDAP includes the spring-ldap-core-tiger.jar distributable, which adds
|
||||
a thin layer of Java 5 functionality on top of Spring LDAP.</para>
|
||||
|
||||
<para>The <literal>SimpleLdapTemplate</literal> class adds search and lookup methods that take a
|
||||
<literal>ParameterizedContextMapper</literal>, adding generics support to these methods.</para>
|
||||
|
||||
<para><literal>ParametrizedContextMapper</literal> is a typed version of <literal>ContextMapper</literal>,
|
||||
which simplifies working with searches and lookups:
|
||||
<example>
|
||||
<title>Using <literal>ParameterizedContextMapper</literal></title>
|
||||
<programlisting>public List<Person> getAllPersons(){
|
||||
return simpleLdapTemplate.search("", "(objectclass=person)",
|
||||
new <emphasis role="bold">ParameterizedContextMapper<Person></emphasis>() {
|
||||
public <emphasis role="bold">Person</emphasis> mapFromContext(Object ctx) {
|
||||
DirContextAdapter adapter = (DirContextAdapter) ctx;
|
||||
Person person = new Person();
|
||||
// Fill the domain object with data from the DirContextAdapter
|
||||
|
||||
return person;
|
||||
}
|
||||
};
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
223
core/docs/reference/src/transactions.xml
Normal file
@@ -0,0 +1,223 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<chapter id="transactions">
|
||||
<title>Transaction Support</title>
|
||||
|
||||
<sect1 id="transactions-intro">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>Programmers used to working with relational databases coming to the LDAP
|
||||
world often express surprise to the fact that there is no notion of transactions.
|
||||
It is not specified in the protocol, and thus no servers support it.
|
||||
Recognizing that this may be a major problem, Spring LDAP provides support for client-side,
|
||||
compensating transactions on LDAP resources.</para>
|
||||
|
||||
<para>LDAP transaction support is provided by <literal>ContextSourceTransactionManager</literal>, a
|
||||
<literal>PlatformTransactionManager</literal> implementation that manages Spring transaction
|
||||
support for LDAP operations. Along with its collaborators it keeps track of the LDAP operations
|
||||
performed in a transaction, making record of the state before each operation and taking steps to
|
||||
restore the initial state should the transaction need to be rolled back.</para>
|
||||
<para>In addition to the actual transaction management, Spring LDAP transaction support also
|
||||
makes sure that the same <literal>DirContext</literal> instance will be used throughout the same transaction,
|
||||
i.e. the <literal>DirContext</literal> will not actually be closed until the transaction is finished,
|
||||
allowing for more efficient resources usage.</para>
|
||||
<para>
|
||||
<note>It is important to note that while the approach used by Spring LDAP to provide transaction support
|
||||
is sufficient for many cases it is by no means "real" transactions in the traditional sense.
|
||||
The server is completely unaware of the transactions, so e.g. if the connection is broken there will
|
||||
be no hope to rollback the transaction. While this should be carefully considered it should also be noted
|
||||
that the alternative will be to operate without any transaction support whatsoever; this is pretty much
|
||||
as good as it gets.</note>
|
||||
<note>The client side transaction support will add some overhead in addition to the work required
|
||||
by the original operations. While this overhead should not be something to worry about in most cases,
|
||||
if your application will not perform several LDAP operations within the same
|
||||
transaction (e.g. a <literal>modifyAttributes</literal> followed by a <literal>rebind</literal>), or
|
||||
if transaction synchronization with a JDBC data source is not required (see below) there will be nothing to gain
|
||||
by using the LDAP transaction support.</note>
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="transactions-configuration">
|
||||
<title>Configuration</title>
|
||||
<para>
|
||||
Configuring Spring LDAP transactions should look very familiar if you're used to configuring Spring transactions.
|
||||
You will create a <literal>TransactionManager</literal> instance and wrap your target object using a
|
||||
<literal>TransactionProxyFactoryBean</literal>. In addition to this, you will also need to wrap your
|
||||
<literal>ContextSource</literal> in a <literal>TransactionAwareContextSourceProxy</literal>.
|
||||
<informalexample>
|
||||
<programlisting><beans>
|
||||
...
|
||||
<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource">
|
||||
<property name="url" value="ldap://localhost:389" />
|
||||
<property name="base" value="dc=example,dc=com" />
|
||||
<property name="userDn" value="cn=Manager" />
|
||||
<property name="password" value="secret" />
|
||||
</bean>
|
||||
|
||||
<bean id="contextSource"
|
||||
class="org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy">
|
||||
<constructor-arg ref="contextSourceTarget" />
|
||||
</bean>
|
||||
|
||||
<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
|
||||
<constructor-arg ref="contextSource" />
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager"
|
||||
class="org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManager">
|
||||
<constructor-arg ref="contextSource" />
|
||||
</bean>
|
||||
|
||||
<bean id="myDataAccessObjectTarget" class="com.example.MyDataAccessObject">
|
||||
<property name="ldapTemplate" ref="ldapTemplate" />
|
||||
</bean>
|
||||
|
||||
<bean id="myDataAccessObject"
|
||||
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
|
||||
<property name="transactionManager" ref="transactionManager" />
|
||||
<property name="target" ref="myDataAccessObjectTarget" />
|
||||
<property name="transactionAttributes">
|
||||
<props>
|
||||
<prop key="*">PROPAGATION_REQUIRES_NEW</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
...</programlisting>
|
||||
</informalexample>
|
||||
In a real world example you would probably apply the transactions on the service object level
|
||||
rather than the DAO level; the above serves as an example to demonstrate the general idea.
|
||||
<note>You'll notice that the actual <literal>ContextSource</literal> and DAO instances get ids with a
|
||||
"Target" suffix. The beans you will actually refer to are the Proxies that are created
|
||||
around the targets; <literal>contextSource</literal> and <literal>myDataAccessObject</literal></note>
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="jdbc-transaction-integration">
|
||||
<title>JDBC Transaction Integration</title>
|
||||
<para>A common use case when working against LDAP is that some of the data is stored in the LDAP tree, but
|
||||
other data is stored in a relational database. In this case, transaction support becomes even more important,
|
||||
since the update of the different resources should be synchronized.</para>
|
||||
<para>While actual XA transactions is not supported, support is provided to conceptually wrap JDBC and LDAP
|
||||
access within the same transaction using the <literal>ContextSourceAndDataSourceTransactionManager</literal>.
|
||||
A <literal>DataSource</literal> and a <literal>ContextSource</literal> is supplied to the
|
||||
<literal>ContextSourceAndDataSourceTransactionManager</literal>, which will then manage the two transactions,
|
||||
virtually as if they were one. When performing a commit, the JDBC part of the operation will always
|
||||
be performed first, allowing both transactions to be rolled back should the JDBC commit fail. The JDBC
|
||||
part of the transaction is managed exactly as in <literal>DataSourceTransactionManager</literal>, except that
|
||||
nested transactions is not supported.
|
||||
<note>Once again it should be noted that the provided support is all client side. The wrapped transaction is not
|
||||
an XA transaction. No two-phase as such commit is performed, as the LDAP server will be unable to vote on its outcome.
|
||||
Once again, however, for the majority of cases the supplied support will be sufficient.</note></para>
|
||||
</sect1>
|
||||
<sect1 id="jdbc-transaction-integration">
|
||||
<title>Hibernate Transaction Integration</title>
|
||||
<para>If Hibernate is used for relational database persistence, transansaction integration can be achieved using
|
||||
<literal>ContextSourceAndHibernateTransactionManager</literal>. The general idea is exactly the same
|
||||
as for JDBC integration, only integratino is made against an underlying <literal>HibernateTransactionManager</literal>
|
||||
rather than a <literal>DataSourceTransactionManager</literal>.</para>
|
||||
</sect1>
|
||||
<sect1 id="compensating-transactions-explained">
|
||||
<title>LDAP Compensating Transactions Explained</title>
|
||||
<para>Spring LDAP manages compensating transactions by making record of the state in the LDAP tree
|
||||
before each modifying operation (<literal>bind</literal>, <literal>unbind</literal>, <literal>rebind</literal>,
|
||||
<literal>modifyAttributes</literal>, and <literal>rename</literal>).</para>
|
||||
<para>This enables the system
|
||||
to perform compensating operations should the transaction need to be rolled back. In many cases the
|
||||
compensating operation is pretty straightforward. E.g. the compensating rollback operation for a
|
||||
<literal>bind</literal> operation will quite obviously be to unbind the entry. Other operations however require
|
||||
a different, more complicated approach because of some particular characteristics of LDAP databases. Specifically,
|
||||
it is not always possible to get the values of all <literal>Attributes</literal> of an entry, making the above
|
||||
strategy insufficient for e.g. an <literal>unbind</literal> operation.</para>
|
||||
<para>This is why each modifying operation performed within a Spring LDAP managed transaction is internally
|
||||
split up in four distinct operations - a recording operation, a preparation operation, a commit operation,
|
||||
and a rollback operation. The specifics for each LDAP operation is described in the table below:</para>
|
||||
<table frame="all">
|
||||
<tgroup cols='5' align='left' colsep='1' rowsep='1'>
|
||||
<colspec colname="c1" />
|
||||
<colspec colname="c2" />
|
||||
<colspec colname="c3" />
|
||||
<colspec colname="c4" />
|
||||
<colspec colname="c5" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>LDAP Operation</entry>
|
||||
<entry>Recording</entry>
|
||||
<entry>Preparation</entry>
|
||||
<entry>Commit</entry>
|
||||
<entry>Rollback</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>bind</literal></entry>
|
||||
<entry>Make record of the DN of the entry to bind.</entry>
|
||||
<entry>Bind the entry.</entry>
|
||||
<entry>No operation.</entry>
|
||||
<entry>Unbind the entry using the recorded DN.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>rename</literal></entry>
|
||||
<entry>Make record of the original and target DN.</entry>
|
||||
<entry>Rename the entry.</entry>
|
||||
<entry>No operation.</entry>
|
||||
<entry>Rename the entry back to its original DN.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>unbind</literal></entry>
|
||||
<entry>Make record of the original DN and calculate a temporary DN.</entry>
|
||||
<entry>Rename the entry to the temporary location.</entry>
|
||||
<entry>Unbind the temporary entry.</entry>
|
||||
<entry>Rename the entry from the temporary location back to its original DN.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>rebind</literal></entry>
|
||||
<entry>Make record of the original DN and the new <literal>Attributes</literal>, and calculate a temporary DN.</entry>
|
||||
<entry>Rename the entry to a temporary location.</entry>
|
||||
<entry>Bind the new <literal>Attributes</literal> at the original DN, and unbind the original entry
|
||||
from its temporary location.</entry>
|
||||
<entry>Rename the entry from the temporary location back to its original DN.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>modifyAttributes</literal></entry>
|
||||
<entry>Make record of the DN of the entry to modify and calculate compensating <literal>ModificationItem</literal>s
|
||||
for the modifications to be done.</entry>
|
||||
<entry>Perform the <literal>modifyAttributes</literal> operation.</entry>
|
||||
<entry>No operation.</entry>
|
||||
<entry>Perform a <literal>modifyAttributes</literal> operation using the calculated compensating
|
||||
<literal>ModificationItem</literal>s.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<para>A more detailed description of the internal workings of the Spring LDAP transaction support is available in the
|
||||
javadocs.</para>
|
||||
<sect2 id="renaming-strategies">
|
||||
<title>Renaming Strategies</title>
|
||||
As described in the table above, the transaction management of some operations require the original entry affected
|
||||
by the operation to be temporarily renamed before the actual modification can be made in the commit.
|
||||
The manner in which the temporary DN of the entry is calculated is managed by a <literal>TempEntryRenamingStrategy</literal>
|
||||
supplied to the <literal>ContextSourceTransactionManager</literal>. Two implementations are supplied with Spring LDAP,
|
||||
but if specific behaviour is required a custom implementation can easily be implemented by the user. The
|
||||
provided <literal>TempEntryRenamingStrategy</literal> implementations are:
|
||||
<itemizedlist>
|
||||
<listitem><para><literal>DefaultTempEntryRenamingStrategy</literal> (the default). Adds a suffix to the least significant
|
||||
part of the entry DN. E.g. for the DN <literal>cn=john doe, ou=users</literal>, this strategy would return the
|
||||
temporary DN <literal>cn=john doe_temp, ou=users</literal>. The suffix is configurable using the <literal>tempSuffix</literal>
|
||||
property</para></listitem>
|
||||
<listitem><para><literal>DifferentSubtreeTempEntryRenamingStrategy</literal>. Takes the least significant part of the DN
|
||||
and appends a subtree DN to this. This makes all temporary entries be placed at a specific location in the LDAP tree.
|
||||
The temporary subtree DN is configured using the <literal>subtreeNode</literal> property. E.g., if
|
||||
<literal>subtreeNode</literal> is <literal>ou=tempEntries</literal> and the original DN of the entry is
|
||||
<literal>cn=john doe, ou=users</literal>, the temporary DN will be <literal>cn=john doe, ou=tempEntries</literal>.
|
||||
Note that the configured subtree node needs to be present in the LDAP tree.</para></listitem>
|
||||
</itemizedlist>
|
||||
<note>
|
||||
There are some situations where the <literal>DefaultTempEntryRenamingStrategy</literal> will not work. E.g. if your are planning
|
||||
to do recursive deletes you'll need to use <literal>DifferentSubtreeTempEntryRenamingStrategy</literal>. This is because
|
||||
the recursive delete operation actually consists of a depth-first delete of each node in the sub tree individually.
|
||||
Since it is not allowed to rename an entry that has any children, and <literal>DefaultTempEntryRenamingStrategy</literal> would
|
||||
leave each node in the same subtree (with a different name) in stead of actually removing it, this operation would fail.
|
||||
When in doubt, use <literal>DifferentSubtreeTempEntryRenamingStrategy</literal>.
|
||||
</note>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
475
core/docs/reference/styles/fopdf.xsl
Normal file
@@ -0,0 +1,475 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!ENTITY db_xsl_path "../lib/docbook-xsl/">
|
||||
<!ENTITY admon_gfx_path "images/admons/">
|
||||
<!ENTITY copyright "©">
|
||||
]>
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0"
|
||||
xmlns="http://www.w3.org/TR/xhtml1/transitional"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
exclude-result-prefixes="#default">
|
||||
|
||||
<xsl:import href="&db_xsl_path;/fo/docbook.xsl"/>
|
||||
|
||||
<!--###################################################
|
||||
Custom Title Page
|
||||
################################################### -->
|
||||
|
||||
<xsl:template name="book.titlepage.recto">
|
||||
<fo:block>
|
||||
<fo:table table-layout="fixed" width="175mm">
|
||||
<fo:table-column column-width="175mm"/>
|
||||
<fo:table-body>
|
||||
<fo:table-row>
|
||||
<fo:table-cell text-align="center">
|
||||
<fo:block>
|
||||
<fo:external-graphic src="file:images/logo.png"/>
|
||||
</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 ©right; 2005-2006 </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 LDAP (</xsl:text><xsl:value-of select="//releaseinfo" /><xsl:text>)</xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:variable>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$sequence='blank'">
|
||||
<xsl:if test="$position = 'center'">
|
||||
<xsl:value-of select="$Version" />
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
<!-- for double sided printing, print page numbers on alternating sides (of the page) -->
|
||||
<xsl:when test="$double.sided != 0">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$sequence = 'even' and $position='left'">
|
||||
<fo:page-number />
|
||||
</xsl:when>
|
||||
<xsl:when test="$sequence = 'odd' and $position='right'">
|
||||
<fo:page-number />
|
||||
</xsl:when>
|
||||
<xsl:when test="$position='center'">
|
||||
<xsl:value-of select="$Version" />
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<!-- for single sided printing, print all page numbers on the right (of the page) -->
|
||||
<xsl:when test="$double.sided = 0">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$position='center'">
|
||||
<xsl:value-of select="$Version" />
|
||||
</xsl:when>
|
||||
<xsl:when test="$position='right'">
|
||||
<fo:page-number />
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Custom Toc Line
|
||||
################################################### -->
|
||||
|
||||
<!-- The default DocBook XSL TOC printing is seriously broken... -->
|
||||
<xsl:template name="toc.line">
|
||||
<xsl:variable name="id">
|
||||
<xsl:call-template name="object.id"/>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:variable name="label">
|
||||
<xsl:apply-templates select="." mode="label.markup"/>
|
||||
</xsl:variable>
|
||||
|
||||
<!-- justify-end removed from block attributes (space problem in title.markup) -->
|
||||
<fo:block end-indent="{$toc.indent.width}pt"
|
||||
last-line-end-indent="-{$toc.indent.width}pt"
|
||||
white-space-treatment="preserve"
|
||||
text-align="left"
|
||||
white-space-collapse="false">
|
||||
<fo:inline keep-with-next.within-line="always">
|
||||
<!-- print Chapters in bold style -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="local-name(.) = 'chapter'">
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
<fo:basic-link internal-destination="{$id}">
|
||||
<xsl:if test="$label != ''">
|
||||
<xsl:copy-of select="$label"/>
|
||||
<fo:inline white-space-treatment="preserve"
|
||||
white-space-collapse="false">
|
||||
<xsl:value-of select="$autotoc.label.separator"/>
|
||||
</fo:inline>
|
||||
</xsl:if>
|
||||
<xsl:apply-templates select="." mode="title.markup"/>
|
||||
</fo:basic-link>
|
||||
</fo:inline>
|
||||
<fo:inline keep-together.within-line="always">
|
||||
<xsl:text> </xsl:text>
|
||||
<fo:leader leader-pattern="dots"
|
||||
leader-pattern-width="3pt"
|
||||
leader-alignment="reference-area"
|
||||
keep-with-next.within-line="always"/>
|
||||
<xsl:text> </xsl:text>
|
||||
<fo:basic-link internal-destination="{$id}">
|
||||
<fo:page-number-citation ref-id="{$id}"/>
|
||||
</fo:basic-link>
|
||||
</fo:inline>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Extensions
|
||||
################################################### -->
|
||||
|
||||
<!-- These extensions are required for table printing and other stuff -->
|
||||
<xsl:param name="use.extensions">1</xsl:param>
|
||||
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||
<xsl:param name="callout.extensions">1</xsl:param>
|
||||
<!-- FOP provide only PDF Bookmarks at the moment -->
|
||||
<xsl:param name="fop.extensions">1</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Table Of Contents
|
||||
################################################### -->
|
||||
|
||||
<!-- Generate the TOCs for named components only -->
|
||||
<xsl:param name="generate.toc">
|
||||
book toc
|
||||
</xsl:param>
|
||||
|
||||
<!-- Show only Sections up to level 3 in the TOCs -->
|
||||
<xsl:param name="toc.section.depth">2</xsl:param>
|
||||
|
||||
<!-- Dot and Whitespace as separator in TOC between Label and Title-->
|
||||
<xsl:param name="autotoc.label.separator" select="'. '"/>
|
||||
|
||||
|
||||
<!--###################################################
|
||||
Paper & Page Size
|
||||
################################################### -->
|
||||
|
||||
<!-- Paper type, no headers on blank pages, no double sided printing -->
|
||||
<xsl:param name="paper.type" select="'A4'"/>
|
||||
<xsl:param name="double.sided">0</xsl:param>
|
||||
<xsl:param name="headers.on.blank.pages">0</xsl:param>
|
||||
<xsl:param name="footers.on.blank.pages">0</xsl:param>
|
||||
|
||||
<!-- Space between paper border and content (chaotic stuff, don't touch) -->
|
||||
<xsl:param name="page.margin.top">5mm</xsl:param>
|
||||
<xsl:param name="region.before.extent">10mm</xsl:param>
|
||||
<xsl:param name="body.margin.top">10mm</xsl:param>
|
||||
|
||||
<xsl:param name="body.margin.bottom">15mm</xsl:param>
|
||||
<xsl:param name="region.after.extent">10mm</xsl:param>
|
||||
<xsl:param name="page.margin.bottom">0mm</xsl:param>
|
||||
|
||||
<xsl:param name="page.margin.outer">18mm</xsl:param>
|
||||
<xsl:param name="page.margin.inner">18mm</xsl:param>
|
||||
|
||||
<!-- No intendation of Titles -->
|
||||
<xsl:param name="title.margin.left">0pc</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Fonts & Styles
|
||||
################################################### -->
|
||||
|
||||
<!-- Left aligned text and no hyphenation -->
|
||||
<xsl:param name="alignment">justify</xsl:param>
|
||||
<xsl:param name="hyphenate">false</xsl:param>
|
||||
|
||||
<!-- Default Font size -->
|
||||
<xsl:param name="body.font.master">11</xsl:param>
|
||||
<xsl:param name="body.font.small">8</xsl:param>
|
||||
|
||||
<!-- Line height in body text -->
|
||||
<xsl:param name="line-height">1.4</xsl:param>
|
||||
|
||||
<!-- Monospaced fonts are smaller than regular text -->
|
||||
<xsl:attribute-set name="monospace.properties">
|
||||
<xsl:attribute name="font-family">
|
||||
<xsl:value-of select="$monospace.font.family"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="font-size">0.8em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Tables
|
||||
################################################### -->
|
||||
|
||||
<!-- The table width should be adapted to the paper size -->
|
||||
<xsl:param name="default.table.width">17.4cm</xsl:param>
|
||||
|
||||
<!-- Some padding inside tables -->
|
||||
<xsl:attribute-set name="table.cell.padding">
|
||||
<xsl:attribute name="padding-left">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">4pt</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Only hairlines as frame and cell borders in tables -->
|
||||
<xsl:param name="table.frame.border.thickness">0.1pt</xsl:param>
|
||||
<xsl:param name="table.cell.border.thickness">0.1pt</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Labels
|
||||
################################################### -->
|
||||
|
||||
<!-- Label Chapters and Sections (numbering) -->
|
||||
<xsl:param name="chapter.autolabel">1</xsl:param>
|
||||
<xsl:param name="section.autolabel" select="1"/>
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||
|
||||
<!--###################################################
|
||||
Titles
|
||||
################################################### -->
|
||||
|
||||
<!-- Chapter title size -->
|
||||
<xsl:attribute-set name="chapter.titlepage.recto.style">
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.8"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Why is the font-size for chapters hardcoded in the XSL FO templates?
|
||||
Let's remove it, so this sucker can use our attribute-set only... -->
|
||||
<xsl:template match="title" mode="chapter.titlepage.recto.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
xsl:use-attribute-sets="chapter.titlepage.recto.style">
|
||||
<xsl:call-template name="component.title">
|
||||
<xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/>
|
||||
</xsl:call-template>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Sections 1, 2 and 3 titles have a small bump factor and padding -->
|
||||
<xsl:attribute-set name="section.title.level1.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.5"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="section.title.level2.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.25"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="section.title.level3.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.0"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Titles of formal objects (tables, examples, ...) -->
|
||||
<xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing">
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="hyphenate">false</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.8em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Programlistings
|
||||
################################################### -->
|
||||
|
||||
<!-- Verbatim text formatting (programlistings) -->
|
||||
<xsl:attribute-set name="monospace.verbatim.properties">
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.small * 1.0"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="verbatim.properties">
|
||||
<xsl:attribute name="space-before.minimum">1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.optimum">1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">1em</xsl:attribute>
|
||||
<xsl:attribute name="border-color">#444444</xsl:attribute>
|
||||
<xsl:attribute name="border-style">solid</xsl:attribute>
|
||||
<xsl:attribute name="border-width">0.1pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-right">0.5em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Shade (background) programlistings -->
|
||||
<xsl:param name="shade.verbatim">1</xsl:param>
|
||||
<xsl:attribute-set name="shade.verbatim.style">
|
||||
<xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Callouts
|
||||
################################################### -->
|
||||
|
||||
<!-- Use images for callouts instead of (1) (2) (3) -->
|
||||
<xsl:param name="callout.graphics">0</xsl:param>
|
||||
<xsl:param name="callout.unicode">1</xsl:param>
|
||||
|
||||
<!-- Place callout marks at this column in annotated areas -->
|
||||
<xsl:param name="callout.defaultcolumn">90</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Admonitions
|
||||
################################################### -->
|
||||
|
||||
<!-- Use nice graphics for admonitions -->
|
||||
<xsl:param name="admon.graphics">'1'</xsl:param>
|
||||
<xsl:param name="admon.graphics.path">&admon_gfx_path;</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Misc
|
||||
################################################### -->
|
||||
|
||||
<!-- Placement of titles -->
|
||||
<xsl:param name="formal.title.placement">
|
||||
figure after
|
||||
example before
|
||||
equation before
|
||||
table before
|
||||
procedure before
|
||||
</xsl:param>
|
||||
|
||||
<!-- Format Variable Lists as Blocks (prevents horizontal overflow) -->
|
||||
<xsl:param name="variablelist.as.blocks">1</xsl:param>
|
||||
|
||||
<!-- The horrible list spacing problems -->
|
||||
<xsl:attribute-set name="list.block.spacing">
|
||||
<xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
colored and hyphenated links
|
||||
################################################### -->
|
||||
<xsl:template match="ulink">
|
||||
<fo:basic-link external-destination="{@url}"
|
||||
xsl:use-attribute-sets="xref.properties"
|
||||
text-decoration="underline"
|
||||
color="blue">
|
||||
<xsl:choose>
|
||||
<xsl:when test="count(child::node())=0">
|
||||
<xsl:value-of select="@url"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:apply-templates/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</fo:basic-link>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
270
core/docs/reference/styles/html.css
Normal file
@@ -0,0 +1,270 @@
|
||||
BODY {
|
||||
text-align: justify;
|
||||
margin-right: 2em;
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
A[accesskey^="p"] {
|
||||
font-family: Verdana, Arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
color: #003399;
|
||||
}
|
||||
|
||||
A[accesskey^="u"] {
|
||||
font-family: Verdana, Arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
color: #003399;
|
||||
}
|
||||
|
||||
A[accesskey^="h"] {
|
||||
font-family: Verdana, Arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
color: #003399;
|
||||
}
|
||||
|
||||
A[accesskey^="n"] {
|
||||
font-family: Verdana, Arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
color: #003399;
|
||||
}
|
||||
|
||||
A {
|
||||
color: #003399;
|
||||
font-family: Verdana, Arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
A:active {
|
||||
color: #003399;
|
||||
}
|
||||
|
||||
A:visited {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
P {
|
||||
font-family: Verdana, Arial;
|
||||
}
|
||||
|
||||
DT {
|
||||
font-family: Verdana, Arial;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
P, DL, DT, DD, BLOCKQUOTE {
|
||||
color: #000000;
|
||||
margin-bottom: 3px;
|
||||
margin-top: 3px;
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
OL, UL, P {
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
P, BLOCKQUOTE {
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
P.releaseinfo {
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
font-family: Verdana, Arial, helvetica, sans-serif;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
P.pubdate {
|
||||
font-size: 120%; font-weight: bold;
|
||||
font-family: Verdana, Arial, helvetica, sans-serif;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
TD, TH, SPAN {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
TD[width^="40%"] {
|
||||
font-family: Verdana, Arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
color: #003399;
|
||||
}
|
||||
|
||||
TABLE[summary^="Navigation header"] tbody tr th[colspan^="3"] {
|
||||
font-family: Verdana, Arial, helvetica, sans-serif;
|
||||
}
|
||||
|
||||
BLOCKQUOTE {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
H1, H2, H3, H4, H5, 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 thin black;
|
||||
empty-cells: hide;
|
||||
margin: 10px 0px 30px 50px;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
div.table {
|
||||
margin: 30px 0 30 0;
|
||||
border: 1px dashed gray;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
div.table > p.title {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
table[summary^="Navigation footer"] {
|
||||
border-collapse: collapse;
|
||||
border-spacing:0;
|
||||
border: 1px thin black;
|
||||
empty-cells: hide;
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table[summary^="Note"], table[summary^="Warning"], table[summary^="Tip"] {
|
||||
border-collapse: collapse;
|
||||
border-spacing:0;
|
||||
border: 1px thin black;
|
||||
empty-cells: hide;
|
||||
margin: 10px 0 10 -20;
|
||||
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 {
|
||||
background-color: #e4eff3;
|
||||
}
|
||||
|
||||
PRE {
|
||||
font-size: 110%;
|
||||
padding: 5px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #CCCCCC;
|
||||
background-color: #F4F4F4;
|
||||
}
|
||||
|
||||
UL, OL, LI {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
HR {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: #CCCCCC;
|
||||
border-width: 0px;
|
||||
padding: 0px;
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
.variablelist {
|
||||
padding-top: 10;
|
||||
padding-bottom:10;
|
||||
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;
|
||||
}
|
||||
|
||||
.programlisting * .classname {
|
||||
font-size: 95%;
|
||||
}
|
||||
|
||||
.programlisting * .interfacename {
|
||||
font-size: 95%;
|
||||
}
|
||||
|
||||
.programlisting * .literal {
|
||||
font-size: 95%;
|
||||
}
|
||||
|
||||
.property {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
}
|
||||
100
core/docs/reference/styles/html.xsl
Normal file
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
This is the XSL HTML configuration file for the Spring
|
||||
Reference Documentation.
|
||||
-->
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!ENTITY db_xsl_path "../lib/docbook-xsl/">
|
||||
<!ENTITY callout_gfx_path "images/callouts/">
|
||||
<!ENTITY admon_gfx_path "images/admons/">
|
||||
]>
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0"
|
||||
xmlns="http://www.w3.org/TR/xhtml1/transitional"
|
||||
exclude-result-prefixes="#default">
|
||||
|
||||
<xsl:import href="&db_xsl_path;/html/docbook.xsl"/>
|
||||
|
||||
<!--###################################################
|
||||
HTML Settings
|
||||
################################################### -->
|
||||
|
||||
<xsl:param name="html.stylesheet">../styles/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">1</xsl:param>
|
||||
<xsl:param name="callout.graphics.path">&callout_gfx_path;</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>
|
||||
<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>
|
||||
103
core/docs/reference/styles/html_chunk.xsl
Normal file
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!--
|
||||
This is the XSL HTML configuration file for the Spring
|
||||
Reference Documentation.
|
||||
-->
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!ENTITY db_xsl_path "../lib/docbook-xsl/">
|
||||
<!ENTITY callout_gfx_path "images/callouts/">
|
||||
<!ENTITY admon_gfx_path "images/admons/">
|
||||
]>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns="http://www.w3.org/TR/xhtml1/transitional"
|
||||
exclude-result-prefixes="#default">
|
||||
<xsl:import href="&db_xsl_path;/html/chunk.xsl" />
|
||||
<!--###################################################
|
||||
HTML Settings
|
||||
################################################### -->
|
||||
<xsl:param name="chunk.section.depth">'5'</xsl:param>
|
||||
<xsl:param name="use.id.as.filename">'1'</xsl:param>
|
||||
<xsl:param name="html.stylesheet">../styles/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">1</xsl:param>
|
||||
<xsl:param name="callout.graphics.path">&callout_gfx_path;</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>
|
||||
<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
|
||||
################################################### -->
|
||||
|
||||
<!-- lets have a Spring and I21 banner across the top of each page -->
|
||||
<xsl:template name="user.header.navigation">
|
||||
<div style="background-color:#31430f;border:none;height:110px;border:1px solid black;">
|
||||
<a style="border:none;background: url();" href="http://www.springframework.org/" title="The Spring Framework">
|
||||
<img style="border:none;" src="images/banner4.jpg"/>
|
||||
</a>
|
||||
<a style="border:none;background: url();" href="http://www.interface21.com/" title="Interface21 - Spring from the Source">
|
||||
<img style="border:none;position:absolute;right:32px;" src="images/bannerR.gif"/>
|
||||
</a>
|
||||
</div>
|
||||
</xsl:template>
|
||||
|
||||
<!-- no header navigation -->
|
||||
<xsl:template name="header.navigation"/>
|
||||
<xsl:param name="navig.showtitles">1</xsl:param>
|
||||
|
||||
</xsl:stylesheet>
|
||||
197
core/docs/reference/styles/tld.to.docbook.xsl
Normal file
@@ -0,0 +1,197 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright 2002-2006 the original author or authors.
|
||||
|
||||
Licensed 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.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Effects the transformation of taglib XML to DocBook XML.
|
||||
|
||||
Author: Rick Evans (based on Tim - katentim - Nolan's original stylesheet)
|
||||
-->
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:xalan="http://xml.apache.org/xalan">
|
||||
|
||||
<xsl:output
|
||||
method="xml"
|
||||
indent="yes"
|
||||
xalan:indent-amount="3"
|
||||
omit-xml-declaration="no"/>
|
||||
|
||||
<xsl:param name="title"/>
|
||||
|
||||
<xsl:template match="taglib">
|
||||
<xsl:element name="appendix">
|
||||
<xsl:attribute name="id">
|
||||
<xsl:value-of select="$title"/>
|
||||
</xsl:attribute>
|
||||
<xsl:element name="title"><xsl:value-of select="$title"/></xsl:element>
|
||||
|
||||
<xsl:element name="section">
|
||||
<xsl:attribute name="id">
|
||||
<xsl:value-of select="$title"/>
|
||||
<xsl:text>-intro</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:element name="title"><xsl:text>Introduction</xsl:text></xsl:element>
|
||||
</xsl:element>
|
||||
|
||||
<xsl:element name="para">
|
||||
<xsl:text>This appendix describes the </xsl:text>
|
||||
<xsl:element name="literal">
|
||||
<xsl:value-of select="$title"/>
|
||||
</xsl:element>
|
||||
<xsl:text> tag library descriptor.</xsl:text>
|
||||
</xsl:element>
|
||||
<xsl:element name="itemizedlist">
|
||||
<xsl:apply-templates select="tag" mode="mini-toc">
|
||||
<xsl:sort select="name" order="ascending"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:element>
|
||||
<xsl:apply-templates select="tag">
|
||||
<xsl:sort select="name" order="ascending"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="tag" mode="mini-toc">
|
||||
<xsl:element name="listitem">
|
||||
<xsl:element name="xref">
|
||||
<xsl:attribute name="linkend">
|
||||
<xsl:call-template name="generate.id">
|
||||
<xsl:with-param name="id">
|
||||
<xsl:value-of select="./name"/>
|
||||
</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:attribute>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="tag">
|
||||
<xsl:element name="section">
|
||||
<xsl:attribute name="id">
|
||||
<xsl:call-template name="generate.id">
|
||||
<xsl:with-param name="id">
|
||||
<xsl:value-of select="./name"/>
|
||||
</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:attribute>
|
||||
<xsl:element name="title">
|
||||
<xsl:text>The </xsl:text>
|
||||
<xsl:element name="literal">
|
||||
<xsl:value-of select="./name"/>
|
||||
</xsl:element>
|
||||
<xsl:text> tag</xsl:text>
|
||||
</xsl:element>
|
||||
<xsl:element name="para">
|
||||
<xsl:value-of select="./description"/>
|
||||
</xsl:element>
|
||||
<xsl:element name="table">
|
||||
<xsl:element name="title">
|
||||
<xsl:text>Attributes</xsl:text>
|
||||
</xsl:element>
|
||||
<xsl:element name="tgroup">
|
||||
<xsl:attribute name="cols">
|
||||
<xsl:text>4</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:element name="colspec">
|
||||
<xsl:attribute name="align">
|
||||
<xsl:text>center</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:element>
|
||||
<xsl:element name="colspec">
|
||||
<xsl:attribute name="align">
|
||||
<xsl:text>center</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:element>
|
||||
<xsl:element name="colspec">
|
||||
<xsl:attribute name="align">
|
||||
<xsl:text>center</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:element>
|
||||
<xsl:element name="colspec">
|
||||
<xsl:attribute name="align">
|
||||
<xsl:text>center</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:element>
|
||||
<xsl:element name="thead">
|
||||
<xsl:element name="row">
|
||||
<xsl:element name="entry">
|
||||
<xsl:attribute name="align">
|
||||
<xsl:text>center</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:text>Attribute</xsl:text>
|
||||
</xsl:element>
|
||||
<xsl:element name="entry">
|
||||
<xsl:attribute name="align">
|
||||
<xsl:text>center</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:text>Required?</xsl:text>
|
||||
</xsl:element>
|
||||
<xsl:element name="entry">
|
||||
<xsl:attribute name="align">
|
||||
<xsl:text>center</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:text>Runtime Expression?</xsl:text>
|
||||
</xsl:element>
|
||||
<xsl:element name="entry">
|
||||
<xsl:attribute name="align">
|
||||
<xsl:text>center</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:text>Description</xsl:text>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
<xsl:element name="tbody">
|
||||
<xsl:apply-templates select="attribute">
|
||||
<xsl:sort select="name" order="ascending"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="attribute">
|
||||
<xsl:element name="row">
|
||||
<xsl:element name="entry">
|
||||
<xsl:element name="para">
|
||||
<xsl:value-of select="name"/>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
<xsl:element name="entry">
|
||||
<xsl:element name="para">
|
||||
<xsl:value-of select="required"/>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
<xsl:element name="entry">
|
||||
<xsl:element name="para">
|
||||
<xsl:value-of select="rtexprvalue"/>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
<xsl:element name="entry">
|
||||
<xsl:element name="para">
|
||||
<xsl:value-of select="description"/>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="generate.id">
|
||||
<xsl:param name="id"/>
|
||||
<xsl:value-of select="$title"/>.<xsl:value-of select="$id"/>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
123
core/docs/reference/styles/xsd.to.docbook.xsl
Normal file
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
Copyright 2002-2006 the original author or authors.
|
||||
|
||||
Licensed 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.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Effects the transformation of the various Spring schema definitions to DocBook XML.
|
||||
|
||||
Author: Rick Evans
|
||||
-->
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xalan="http://xml.apache.org/xalan">
|
||||
|
||||
<xsl:output
|
||||
method="xml"
|
||||
indent="yes"
|
||||
xalan:indent-amount="3"
|
||||
omit-xml-declaration="no"/>
|
||||
|
||||
<xsl:param name="title"/>
|
||||
|
||||
<xsl:template match="xsd:schema">
|
||||
<xsl:element name="appendix">
|
||||
<xsl:attribute name="id">
|
||||
<xsl:value-of select="$title"/>
|
||||
</xsl:attribute>
|
||||
<xsl:element name="title">
|
||||
<xsl:element name="literal">
|
||||
<xsl:value-of select="$title"/>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
|
||||
<xsl:element name="section">
|
||||
<xsl:attribute name="id">
|
||||
<xsl:value-of select="$title"/>
|
||||
<xsl:text>-intro</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:element name="title">
|
||||
<xsl:text>Introduction</xsl:text>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
|
||||
<xsl:element name="para">
|
||||
<xsl:text>This appendix describes the </xsl:text>
|
||||
<xsl:element name="literal">
|
||||
<xsl:value-of select="$title"/>
|
||||
</xsl:element>
|
||||
<xsl:text> schema.</xsl:text>
|
||||
</xsl:element>
|
||||
|
||||
<xsl:element name="itemizedlist">
|
||||
<xsl:apply-templates select="xsd:element" mode="mini-toc">
|
||||
<xsl:sort select="name" order="ascending"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:element>
|
||||
|
||||
<xsl:apply-templates select="xsd:element">
|
||||
<xsl:sort select="name" order="ascending"/>
|
||||
</xsl:apply-templates>
|
||||
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<!--
|
||||
creates the elements of an <itemizedlist/> containing (hyper)links
|
||||
to the actual content
|
||||
-->
|
||||
<xsl:template match="xsd:element" mode="mini-toc">
|
||||
<xsl:element name="listitem">
|
||||
<xsl:element name="xref">
|
||||
<xsl:attribute name="linkend">
|
||||
<xsl:call-template name="generate.id">
|
||||
<xsl:with-param name="id">
|
||||
<xsl:value-of select="@name"/>
|
||||
</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:attribute>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="xsd:element">
|
||||
<xsl:element name="section">
|
||||
<xsl:attribute name="id">
|
||||
<xsl:call-template name="generate.id">
|
||||
<xsl:with-param name="id">
|
||||
<xsl:value-of select="@name"/>
|
||||
</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:attribute>
|
||||
<xsl:element name="title">
|
||||
<xsl:text>The </xsl:text>
|
||||
<xsl:element name="literal">
|
||||
<xsl:value-of select="@name"/>
|
||||
</xsl:element>
|
||||
<xsl:text> element</xsl:text>
|
||||
</xsl:element>
|
||||
<xsl:element name="para">
|
||||
<xsl:text>[TODO : insert the description of the element here]</xsl:text>
|
||||
</xsl:element>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="generate.id">
|
||||
<xsl:param name="id"/>
|
||||
<xsl:value-of select="$title"/>.<xsl:value-of select="$id"/>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||