git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@773 50f2f4bb-b051-0410-bef5-90022cba6387pull/1/head
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project name="spring-framework-reference" default="doc"> |
||||
|
||||
<property name="doc.type" value="reference"/> |
||||
<property name="docbook.build.dir" value="${basedir}"/> |
||||
<property file="${basedir}/../build.properties"/> |
||||
<import file="${basedir}/../spring-build/docbook/default.xml"/> |
||||
|
||||
</project> |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
html { |
||||
padding: 0pt; |
||||
margin: 0pt; |
||||
} |
||||
|
||||
body { |
||||
margin-left: 10%; |
||||
margin-right: 10%; |
||||
font-family: Arial, Sans-serif; |
||||
} |
||||
|
||||
div { |
||||
margin: 0pt; |
||||
} |
||||
|
||||
p { |
||||
text-align: justify; |
||||
} |
||||
|
||||
hr { |
||||
border: 1px solid gray; |
||||
background: gray; |
||||
} |
||||
|
||||
h1,h2,h3 { |
||||
color: #234623; |
||||
font-family: Arial, Sans-serif; |
||||
} |
||||
|
||||
pre { |
||||
line-height: 1.0; |
||||
color: black; |
||||
} |
||||
|
||||
pre.programlisting { |
||||
font-size: 10pt; |
||||
padding: 7pt 3pt; |
||||
border: 1pt solid black; |
||||
background: #eeeeee; |
||||
} |
||||
|
||||
div.table { |
||||
margin: 1em; |
||||
padding: 0.5em; |
||||
text-align: center; |
||||
} |
||||
|
||||
div.table table { |
||||
display: table; |
||||
width: 100%; |
||||
} |
||||
|
||||
div.table td { |
||||
padding-left: 7px; |
||||
padding-right: 7px; |
||||
} |
||||
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 36 KiB |
@ -0,0 +1,125 @@
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<chapter id="dao"> |
||||
<title>DAO support</title> |
||||
<section id="dao-introduction"> |
||||
<title>Introduction</title> |
||||
<para> |
||||
The Data Access Object (DAO) support in Spring is aimed at |
||||
making it easy to work with data access technologies like |
||||
JDBC, Hibernate or JDO in a consistent way. This allows one |
||||
to switch between the aforementioned persistence technologies |
||||
fairly easily and it also allows one to code without worrying |
||||
about catching exceptions that are specific to each technology. |
||||
</para> |
||||
</section> |
||||
<section id="dao-exceptions"> |
||||
<title>Consistent exception hierarchy</title> |
||||
<para> |
||||
Spring provides a convenient translation from technology-specific |
||||
exceptions like <classname>SQLException</classname> to its own |
||||
exception class hierarchy with the |
||||
<classname>DataAccessException</classname> as the root exception. |
||||
These exceptions wrap the original exception so there is never |
||||
any risk that one might lose any information as to what might |
||||
have gone wrong. |
||||
</para> |
||||
<para> |
||||
In addition to JDBC exceptions, Spring can also wrap Hibernate-specific |
||||
exceptions, converting them from proprietary, checked exceptions |
||||
(in the case of versions of Hibernate prior to Hibernate 3.0), to |
||||
a set of focused runtime exceptions (the same is true for JDO and |
||||
JPA exceptions). This allows one to handle most persistence exceptions, |
||||
which are non-recoverable, only in the appropriate layers, without |
||||
having annoying boilerplate catch-and-throw blocks and exception |
||||
declarations in one's DAOs. (One can still trap and handle exceptions |
||||
anywhere one needs to though.) As mentioned above, JDBC exceptions |
||||
(including database-specific dialects) are also converted to the |
||||
same hierarchy, meaning that one can perform some operations with |
||||
JDBC within a consistent programming model. |
||||
</para> |
||||
<para> |
||||
The above holds true for the various template classes in Springs |
||||
support for various ORM frameworks. If one uses the interceptor-based |
||||
classes then the application must care about handling |
||||
<classname>HibernateExceptions</classname> and |
||||
<classname>JDOExceptions</classname> itself, preferably via delegating |
||||
to <classname>SessionFactoryUtils</classname>' |
||||
<methodname>convertHibernateAccessException(..)</methodname> or |
||||
<methodname>convertJdoAccessException</methodname> methods respectively. |
||||
These methods convert the exceptions to ones that are compatible |
||||
with the exceptions in the <literal>org.springframework.dao</literal> |
||||
exception hierarchy. As <classname>JDOExceptions</classname> are |
||||
unchecked, they can simply get thrown too, sacrificing generic DAO |
||||
abstraction in terms of exceptions though. |
||||
</para> |
||||
<para> |
||||
The exception hierarchy that Spring provides can be seen below. |
||||
(Please note that the class hierarchy detailed in the image |
||||
shows only a subset of the entire |
||||
<classname>DataAccessException</classname> hierarchy.) |
||||
</para> |
||||
<mediaobject> |
||||
<imageobject> |
||||
<imagedata fileref="images/DataAccessException.gif" align="center" /> |
||||
</imageobject> |
||||
</mediaobject> |
||||
</section> |
||||
<section id="dao-abstract-superclasses"> |
||||
<title>Consistent abstract classes for DAO support</title> |
||||
<para> |
||||
To make it easier to work with a variety of data access technologies |
||||
such as JDBC, JDO and Hibernate in a consistent way, Spring provides |
||||
a set of <literal>abstract</literal> DAO classes that one can extend. |
||||
These abstract classes have methods for providing the data source and |
||||
any other configuration settings that are specific to the relevant |
||||
data-access technology. |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para> |
||||
<classname>JdbcDaoSupport</classname> - superclass for JDBC data |
||||
access objects. Requires a <interfacename>DataSource</interfacename> |
||||
to be provided; in turn, this class provides a |
||||
<classname>JdbcTemplate</classname> instance initialized from the |
||||
supplied <interfacename>DataSource</interfacename> to subclasses. |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<classname>HibernateDaoSupport</classname> - superclass for |
||||
Hibernate data access objects. Requires a |
||||
<interfacename>SessionFactory</interfacename> to be provided; |
||||
in turn, this class provides a |
||||
<classname>HibernateTemplate</classname> instance initialized |
||||
from the supplied <interfacename>SessionFactory</interfacename> |
||||
to subclasses. Can alternatively be initialized directly via a |
||||
<classname>HibernateTemplate</classname>, to reuse the latters |
||||
settings like <interfacename>SessionFactory</interfacename>, |
||||
flush mode, exception translator, and so forth. |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<classname>JdoDaoSupport</classname> - super class for JDO data |
||||
access objects. Requires a |
||||
<interfacename>PersistenceManagerFactory</interfacename> |
||||
to be provided; in turn, this class provides a |
||||
<classname>JdoTemplate</classname> instance initialized from the |
||||
supplied <interfacename>PersistenceManagerFactory</interfacename> |
||||
to subclasses. |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<classname>JpaDaoSupport</classname> - super class for JPA data |
||||
access objects. Requires a |
||||
<interfacename>EntityManagerFactory</interfacename> to be provided; |
||||
in turn, this class provides a <classname>JpaTemplate</classname> |
||||
instance initialized from the supplied |
||||
<interfacename>EntityManagerFactory</interfacename> to subclasses. |
||||
</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</section> |
||||
|
||||
</chapter> |
||||
@ -0,0 +1,681 @@
@@ -0,0 +1,681 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<appendix id="springbeansdtd"> |
||||
<title><literal>spring-beans-2.0.dtd</literal></title> |
||||
|
||||
<para><programlisting><!-- |
||||
Spring XML Beans DTD, version 2.0 |
||||
Authors: Rod Johnson, Juergen Hoeller, Alef Arendsen, Colin Sampaleanu, Rob Harrop |
||||
|
||||
This defines a simple and consistent way of creating a namespace |
||||
of JavaBeans objects, managed by a Spring BeanFactory, read by |
||||
XmlBeanDefinitionReader (with DefaultBeanDefinitionDocumentReader). |
||||
|
||||
This document type is used by most Spring functionality, including |
||||
web application contexts, which are based on bean factories. |
||||
|
||||
Each "bean" element in this document defines a JavaBean. |
||||
Typically the bean class is specified, along with JavaBean properties |
||||
and/or constructor arguments. |
||||
|
||||
A bean instance can be a "singleton" (shared instance) or a "prototype" |
||||
(independent instance). Further scopes can be provided by extended |
||||
bean factories, for example in a web environment. |
||||
|
||||
References among beans are supported, that is, setting a JavaBean property |
||||
or a constructor argument to refer to another bean in the same factory |
||||
(or an ancestor factory). |
||||
|
||||
As alternative to bean references, "inner bean definitions" can be used. |
||||
Singleton flags of such inner bean definitions are effectively ignored: |
||||
Inner beans are typically anonymous prototypes. |
||||
|
||||
There is also support for lists, sets, maps, and java.util.Properties |
||||
as bean property types or constructor argument types. |
||||
|
||||
For simple purposes, this DTD is sufficient. As of Spring 2.0, |
||||
XSD-based bean definitions are supported as more powerful alternative. |
||||
|
||||
XML documents that conform to this DTD should declare the following doctype: |
||||
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" |
||||
"http://www.springframework.org/dtd/spring-beans-2.0.dtd"> |
||||
--> |
||||
|
||||
|
||||
<!-- |
||||
The document root. A document can contain bean definitions only, |
||||
imports only, or a mixture of both (typically with imports first). |
||||
--> |
||||
<!ELEMENT beans ( |
||||
description?, |
||||
(import | alias | bean)* |
||||
)> |
||||
|
||||
<!-- |
||||
Default values for all bean definitions. Can be overridden at |
||||
the "bean" level. See those attribute definitions for details. |
||||
--> |
||||
<!ATTLIST beans default-lazy-init (true | false) "false"> |
||||
<!ATTLIST beans default-autowire (no | byName | byType | constructor | autodetect) "no"> |
||||
<!ATTLIST beans default-dependency-check (none | objects | simple | all) "none"> |
||||
<!ATTLIST beans default-init-method CDATA #IMPLIED> |
||||
<!ATTLIST beans default-destroy-method CDATA #IMPLIED> |
||||
<!ATTLIST beans default-merge (true | false) "false"> |
||||
|
||||
<!-- |
||||
Element containing informative text describing the purpose of the enclosing |
||||
element. Always optional. |
||||
Used primarily for user documentation of XML bean definition documents. |
||||
--> |
||||
<!ELEMENT description (#PCDATA)> |
||||
|
||||
|
||||
<!-- |
||||
Specifies an XML bean definition resource to import. |
||||
--> |
||||
<!ELEMENT import EMPTY> |
||||
|
||||
<!-- |
||||
The relative resource location of the XML bean definition file to import, |
||||
for example "myImport.xml" or "includes/myImport.xml" or "../myImport.xml". |
||||
--> |
||||
<!ATTLIST import resource CDATA #REQUIRED> |
||||
|
||||
|
||||
<!-- |
||||
Defines an alias for a bean, which can reside in a different definition file. |
||||
--> |
||||
<!ELEMENT alias EMPTY> |
||||
|
||||
<!-- |
||||
The name of the bean to define an alias for. |
||||
--> |
||||
<!ATTLIST alias name CDATA #REQUIRED> |
||||
|
||||
<!-- |
||||
The alias name to define for the bean. |
||||
--> |
||||
<!ATTLIST alias alias CDATA #REQUIRED> |
||||
|
||||
<!-- |
||||
Allows for arbitrary metadata to be attached to a bean definition. |
||||
--> |
||||
<!ELEMENT meta EMPTY> |
||||
|
||||
<!-- |
||||
Specifies the key name of the metadata parameter being defined. |
||||
--> |
||||
<!ATTLIST meta key CDATA #REQUIRED> |
||||
|
||||
<!-- |
||||
Specifies the value of the metadata parameter being defined as a String. |
||||
--> |
||||
<!ATTLIST meta value CDATA #REQUIRED> |
||||
|
||||
<!-- |
||||
Defines a single (usually named) bean. |
||||
|
||||
A bean definition may contain nested tags for constructor arguments, |
||||
property values, lookup methods, and replaced methods. Mixing constructor |
||||
injection and setter injection on the same bean is explicitly supported. |
||||
--> |
||||
<!ELEMENT bean ( |
||||
description?, |
||||
(meta | constructor-arg | property | lookup-method | replaced-method)* |
||||
)> |
||||
|
||||
<!-- |
||||
Beans can be identified by an id, to enable reference checking. |
||||
|
||||
There are constraints on a valid XML id: if you want to reference your bean |
||||
in Java code using a name that's illegal as an XML id, use the optional |
||||
"name" attribute. If neither is given, the bean class name is used as id |
||||
(with an appended counter like "#2" if there is already a bean with that name). |
||||
--> |
||||
<!ATTLIST bean id ID #IMPLIED> |
||||
|
||||
<!-- |
||||
Optional. Can be used to create one or more aliases illegal in an id. |
||||
Multiple aliases can be separated by any number of spaces, commas, or |
||||
semi-colons (or indeed any mixture of the three). |
||||
--> |
||||
<!ATTLIST bean name CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Each bean definition must specify the fully qualified name of the class, |
||||
except if it pure serves as parent for child bean definitions. |
||||
--> |
||||
<!ATTLIST bean class CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Optionally specify a parent bean definition. |
||||
|
||||
Will use the bean class of the parent if none specified, but can |
||||
also override it. In the latter case, the child bean class must be |
||||
compatible with the parent, i.e. accept the parent's property values |
||||
and constructor argument values, if any. |
||||
|
||||
A child bean definition will inherit constructor argument values, |
||||
property values and method overrides from the parent, with the option |
||||
to add new values. If init method, destroy method, factory bean and/or factory |
||||
method are specified, they will override the corresponding parent settings. |
||||
|
||||
The remaining settings will always be taken from the child definition: |
||||
depends on, autowire mode, dependency check, scope, lazy init. |
||||
--> |
||||
<!ATTLIST bean parent CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
The scope of this bean: typically "singleton" (one shared instance, |
||||
which will be returned by all calls to getBean() with the id), |
||||
or "prototype" (independent instance resulting from each call to |
||||
getBean(). Default is "singleton". |
||||
|
||||
Singletons are most commonly used, and are ideal for multi-threaded |
||||
service objects. Further scopes, such as "request" or "session", |
||||
might be supported by extended bean factories (for example, in a |
||||
web environment). |
||||
|
||||
Note: This attribute will not be inherited by child bean definitions. |
||||
Hence, it needs to be specified per concrete bean definition. |
||||
|
||||
Inner bean definitions inherit the singleton status of their containing |
||||
bean definition, unless explicitly specified: The inner bean will be a |
||||
singleton if the containing bean is a singleton, and a prototype if |
||||
the containing bean has any other scope. |
||||
--> |
||||
<!ATTLIST bean scope CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Is this bean "abstract", i.e. not meant to be instantiated itself but |
||||
rather just serving as parent for concrete child bean definitions. |
||||
Default is "false". Specify "true" to tell the bean factory to not try to |
||||
instantiate that particular bean in any case. |
||||
|
||||
Note: This attribute will not be inherited by child bean definitions. |
||||
Hence, it needs to be specified per abstract bean definition. |
||||
--> |
||||
<!ATTLIST bean abstract (true | false) #IMPLIED> |
||||
|
||||
<!-- |
||||
If this bean should be lazily initialized. |
||||
If false, it will get instantiated on startup by bean factories |
||||
that perform eager initialization of singletons. |
||||
|
||||
Note: This attribute will not be inherited by child bean definitions. |
||||
Hence, it needs to be specified per concrete bean definition. |
||||
--> |
||||
<!ATTLIST bean lazy-init (true | false | default) "default"> |
||||
|
||||
<!-- |
||||
Indicates whether or not this bean should be considered when looking |
||||
for candidates to satisfy another beans autowiring requirements. |
||||
--> |
||||
<!ATTLIST bean autowire-candidate (true | false) #IMPLIED> |
||||
|
||||
<!-- |
||||
Optional attribute controlling whether to "autowire" bean properties. |
||||
This is an automagical process in which bean references don't need to be coded |
||||
explicitly in the XML bean definition file, but Spring works out dependencies. |
||||
|
||||
There are 5 modes: |
||||
|
||||
1. "no" |
||||
The traditional Spring default. No automagical wiring. Bean references |
||||
must be defined in the XML file via the <ref> element. We recommend this |
||||
in most cases as it makes documentation more explicit. |
||||
|
||||
2. "byName" |
||||
Autowiring by property name. If a bean of class Cat exposes a dog property, |
||||
Spring will try to set this to the value of the bean "dog" in the current factory. |
||||
If there is no matching bean by name, nothing special happens; |
||||
use dependency-check="objects" to raise an error in that case. |
||||
|
||||
3. "byType" |
||||
Autowiring if there is exactly one bean of the property type in the bean factory. |
||||
If there is more than one, a fatal error is raised, and you can't use byType |
||||
autowiring for that bean. If there is none, nothing special happens; |
||||
use dependency-check="objects" to raise an error in that case. |
||||
|
||||
4. "constructor" |
||||
Analogous to "byType" for constructor arguments. If there isn't exactly one bean |
||||
of the constructor argument type in the bean factory, a fatal error is raised. |
||||
|
||||
5. "autodetect" |
||||
Chooses "constructor" or "byType" through introspection of the bean class. |
||||
If a default constructor is found, "byType" gets applied. |
||||
|
||||
The latter two are similar to PicoContainer and make bean factories simple to |
||||
configure for small namespaces, but doesn't work as well as standard Spring |
||||
behaviour for bigger applications. |
||||
|
||||
Note that explicit dependencies, i.e. "property" and "constructor-arg" elements, |
||||
always override autowiring. Autowire behavior can be combined with dependency |
||||
checking, which will be performed after all autowiring has been completed. |
||||
|
||||
Note: This attribute will not be inherited by child bean definitions. |
||||
Hence, it needs to be specified per concrete bean definition. |
||||
--> |
||||
<!ATTLIST bean autowire (no | byName | byType | constructor | autodetect | default) "default"> |
||||
|
||||
<!-- |
||||
Optional attribute controlling whether to check whether all this |
||||
beans dependencies, expressed in its properties, are satisfied. |
||||
Default is no dependency checking. |
||||
|
||||
"simple" type dependency checking includes primitives and String; |
||||
"objects" includes collaborators (other beans in the factory); |
||||
"all" includes both types of dependency checking. |
||||
|
||||
Note: This attribute will not be inherited by child bean definitions. |
||||
Hence, it needs to be specified per concrete bean definition. |
||||
--> |
||||
<!ATTLIST bean dependency-check (none | objects | simple | all | default) "default"> |
||||
|
||||
<!-- |
||||
The names of the beans that this bean depends on being initialized. |
||||
The bean factory will guarantee that these beans get initialized before. |
||||
|
||||
Note that dependencies are normally expressed through bean properties or |
||||
constructor arguments. This property should just be necessary for other kinds |
||||
of dependencies like statics (*ugh*) or database preparation on startup. |
||||
|
||||
Note: This attribute will not be inherited by child bean definitions. |
||||
Hence, it needs to be specified per concrete bean definition. |
||||
--> |
||||
<!ATTLIST bean depends-on CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Optional attribute for the name of the custom initialization method |
||||
to invoke after setting bean properties. The method must have no arguments, |
||||
but may throw any exception. |
||||
--> |
||||
<!ATTLIST bean init-method CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Optional attribute for the name of the custom destroy method to invoke |
||||
on bean factory shutdown. The method must have no arguments, |
||||
but may throw any exception. |
||||
|
||||
Note: Only invoked on beans whose lifecycle is under full control |
||||
of the factory - which is always the case for singletons, but not |
||||
guaranteed for any other scope. |
||||
--> |
||||
<!ATTLIST bean destroy-method CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Optional attribute specifying the name of a factory method to use to |
||||
create this object. Use constructor-arg elements to specify arguments |
||||
to the factory method, if it takes arguments. Autowiring does not apply |
||||
to factory methods. |
||||
|
||||
If the "class" attribute is present, the factory method will be a static |
||||
method on the class specified by the "class" attribute on this bean |
||||
definition. Often this will be the same class as that of the constructed |
||||
object - for example, when the factory method is used as an alternative |
||||
to a constructor. However, it may be on a different class. In that case, |
||||
the created object will *not* be of the class specified in the "class" |
||||
attribute. This is analogous to FactoryBean behavior. |
||||
|
||||
If the "factory-bean" attribute is present, the "class" attribute is not |
||||
used, and the factory method will be an instance method on the object |
||||
returned from a getBean call with the specified bean name. The factory |
||||
bean may be defined as a singleton or a prototype. |
||||
|
||||
The factory method can have any number of arguments. Autowiring is not |
||||
supported. Use indexed constructor-arg elements in conjunction with the |
||||
factory-method attribute. |
||||
|
||||
Setter Injection can be used in conjunction with a factory method. |
||||
Method Injection cannot, as the factory method returns an instance, |
||||
which will be used when the container creates the bean. |
||||
--> |
||||
<!ATTLIST bean factory-method CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Alternative to class attribute for factory-method usage. |
||||
If this is specified, no class attribute should be used. |
||||
This should be set to the name of a bean in the current or |
||||
ancestor factories that contains the relevant factory method. |
||||
This allows the factory itself to be configured using Dependency |
||||
Injection, and an instance (rather than static) method to be used. |
||||
--> |
||||
<!ATTLIST bean factory-bean CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Bean definitions can specify zero or more constructor arguments. |
||||
This is an alternative to "autowire constructor". |
||||
Arguments correspond to either a specific index of the constructor argument |
||||
list or are supposed to be matched generically by type. |
||||
|
||||
Note: A single generic argument value will just be used once, rather than |
||||
potentially matched multiple times (as of Spring 1.1). |
||||
|
||||
constructor-arg elements are also used in conjunction with the factory-method |
||||
element to construct beans using static or instance factory methods. |
||||
--> |
||||
<!ELEMENT constructor-arg ( |
||||
description?, |
||||
(bean | ref | idref | value | null | list | set | map | props)? |
||||
)> |
||||
|
||||
<!-- |
||||
The constructor-arg tag can have an optional index attribute, |
||||
to specify the exact index in the constructor argument list. Only needed |
||||
to avoid ambiguities, e.g. in case of 2 arguments of the same type. |
||||
--> |
||||
<!ATTLIST constructor-arg index CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
The constructor-arg tag can have an optional type attribute, |
||||
to specify the exact type of the constructor argument. Only needed |
||||
to avoid ambiguities, e.g. in case of 2 single argument constructors |
||||
that can both be converted from a String. |
||||
--> |
||||
<!ATTLIST constructor-arg type CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
A short-cut alternative to a child element "ref bean=". |
||||
--> |
||||
<!ATTLIST constructor-arg ref CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
A short-cut alternative to a child element "value". |
||||
--> |
||||
<!ATTLIST constructor-arg value CDATA #IMPLIED> |
||||
|
||||
|
||||
<!-- |
||||
Bean definitions can have zero or more properties. |
||||
Property elements correspond to JavaBean setter methods exposed |
||||
by the bean classes. Spring supports primitives, references to other |
||||
beans in the same or related factories, lists, maps and properties. |
||||
--> |
||||
<!ELEMENT property ( |
||||
description?, meta*, |
||||
(bean | ref | idref | value | null | list | set | map | props)? |
||||
)> |
||||
|
||||
<!-- |
||||
The property name attribute is the name of the JavaBean property. |
||||
This follows JavaBean conventions: a name of "age" would correspond |
||||
to setAge()/optional getAge() methods. |
||||
--> |
||||
<!ATTLIST property name CDATA #REQUIRED> |
||||
|
||||
<!-- |
||||
A short-cut alternative to a child element "ref bean=". |
||||
--> |
||||
<!ATTLIST property ref CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
A short-cut alternative to a child element "value". |
||||
--> |
||||
<!ATTLIST property value CDATA #IMPLIED> |
||||
|
||||
|
||||
<!-- |
||||
A lookup method causes the IoC container to override the given method and return |
||||
the bean with the name given in the bean attribute. This is a form of Method Injection. |
||||
It's particularly useful as an alternative to implementing the BeanFactoryAware |
||||
interface, in order to be able to make getBean() calls for non-singleton instances |
||||
at runtime. In this case, Method Injection is a less invasive alternative. |
||||
--> |
||||
<!ELEMENT lookup-method EMPTY> |
||||
|
||||
<!-- |
||||
Name of a lookup method. This method should take no arguments. |
||||
--> |
||||
<!ATTLIST lookup-method name CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Name of the bean in the current or ancestor factories that the lookup method |
||||
should resolve to. Often this bean will be a prototype, in which case the |
||||
lookup method will return a distinct instance on every invocation. This |
||||
is useful for single-threaded objects. |
||||
--> |
||||
<!ATTLIST lookup-method bean CDATA #IMPLIED> |
||||
|
||||
|
||||
<!-- |
||||
Similar to the lookup method mechanism, the replaced-method element is used to control |
||||
IoC container method overriding: Method Injection. This mechanism allows the overriding |
||||
of a method with arbitrary code. |
||||
--> |
||||
<!ELEMENT replaced-method ( |
||||
(arg-type)* |
||||
)> |
||||
|
||||
<!-- |
||||
Name of the method whose implementation should be replaced by the IoC container. |
||||
If this method is not overloaded, there's no need to use arg-type subelements. |
||||
If this method is overloaded, arg-type subelements must be used for all |
||||
override definitions for the method. |
||||
--> |
||||
<!ATTLIST replaced-method name CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Bean name of an implementation of the MethodReplacer interface in the current |
||||
or ancestor factories. This may be a singleton or prototype bean. If it's |
||||
a prototype, a new instance will be used for each method replacement. |
||||
Singleton usage is the norm. |
||||
--> |
||||
<!ATTLIST replaced-method replacer CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Subelement of replaced-method identifying an argument for a replaced method |
||||
in the event of method overloading. |
||||
--> |
||||
<!ELEMENT arg-type (#PCDATA)> |
||||
|
||||
<!-- |
||||
Specification of the type of an overloaded method argument as a String. |
||||
For convenience, this may be a substring of the FQN. E.g. all the |
||||
following would match "java.lang.String": |
||||
- java.lang.String |
||||
- String |
||||
- Str |
||||
|
||||
As the number of arguments will be checked also, this convenience can often |
||||
be used to save typing. |
||||
--> |
||||
<!ATTLIST arg-type match CDATA #IMPLIED> |
||||
|
||||
|
||||
<!-- |
||||
Defines a reference to another bean in this factory or an external |
||||
factory (parent or included factory). |
||||
--> |
||||
<!ELEMENT ref EMPTY> |
||||
|
||||
<!-- |
||||
References must specify a name of the target bean. |
||||
The "bean" attribute can reference any name from any bean in the context, |
||||
to be checked at runtime. |
||||
Local references, using the "local" attribute, have to use bean ids; |
||||
they can be checked by this DTD, thus should be preferred for references |
||||
within the same bean factory XML file. |
||||
--> |
||||
<!ATTLIST ref bean CDATA #IMPLIED> |
||||
<!ATTLIST ref local IDREF #IMPLIED> |
||||
<!ATTLIST ref parent CDATA #IMPLIED> |
||||
|
||||
|
||||
<!-- |
||||
Defines a string property value, which must also be the id of another |
||||
bean in this factory or an external factory (parent or included factory). |
||||
While a regular 'value' element could instead be used for the same effect, |
||||
using idref in this case allows validation of local bean ids by the XML |
||||
parser, and name completion by supporting tools. |
||||
--> |
||||
<!ELEMENT idref EMPTY> |
||||
|
||||
<!-- |
||||
ID refs must specify a name of the target bean. |
||||
The "bean" attribute can reference any name from any bean in the context, |
||||
potentially to be checked at runtime by bean factory implementations. |
||||
Local references, using the "local" attribute, have to use bean ids; |
||||
they can be checked by this DTD, thus should be preferred for references |
||||
within the same bean factory XML file. |
||||
--> |
||||
<!ATTLIST idref bean CDATA #IMPLIED> |
||||
<!ATTLIST idref local IDREF #IMPLIED> |
||||
|
||||
|
||||
<!-- |
||||
Contains a string representation of a property value. |
||||
The property may be a string, or may be converted to the required |
||||
type using the JavaBeans PropertyEditor machinery. This makes it |
||||
possible for application developers to write custom PropertyEditor |
||||
implementations that can convert strings to arbitrary target objects. |
||||
|
||||
Note that this is recommended for simple objects only. |
||||
Configure more complex objects by populating JavaBean |
||||
properties with references to other beans. |
||||
--> |
||||
<!ELEMENT value (#PCDATA)> |
||||
|
||||
<!-- |
||||
The value tag can have an optional type attribute, to specify the |
||||
exact type that the value should be converted to. Only needed |
||||
if the type of the target property or constructor argument is |
||||
too generic: for example, in case of a collection element. |
||||
--> |
||||
<!ATTLIST value type CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Denotes a Java null value. Necessary because an empty "value" tag |
||||
will resolve to an empty String, which will not be resolved to a |
||||
null value unless a special PropertyEditor does so. |
||||
--> |
||||
<!ELEMENT null (#PCDATA)> |
||||
|
||||
|
||||
<!-- |
||||
A list can contain multiple inner bean, ref, collection, or value elements. |
||||
Java lists are untyped, pending generics support in Java 1.5, |
||||
although references will be strongly typed. |
||||
A list can also map to an array type. The necessary conversion |
||||
is automatically performed by the BeanFactory. |
||||
--> |
||||
<!ELEMENT list ( |
||||
(bean | ref | idref | value | null | list | set | map | props)* |
||||
)> |
||||
|
||||
<!-- |
||||
Enable/disable merging for collections when using parent/child beans. |
||||
--> |
||||
<!ATTLIST list merge (true | false | default) "default"> |
||||
|
||||
<!-- |
||||
Specify the default Java type for nested values. |
||||
--> |
||||
<!ATTLIST list value-type CDATA #IMPLIED> |
||||
|
||||
|
||||
<!-- |
||||
A set can contain multiple inner bean, ref, collection, or value elements. |
||||
Java sets are untyped, pending generics support in Java 1.5, |
||||
although references will be strongly typed. |
||||
--> |
||||
<!ELEMENT set ( |
||||
(bean | ref | idref | value | null | list | set | map | props)* |
||||
)> |
||||
|
||||
<!-- |
||||
Enable/disable merging for collections when using parent/child beans. |
||||
--> |
||||
<!ATTLIST set merge (true | false | default) "default"> |
||||
|
||||
<!-- |
||||
Specify the default Java type for nested values. |
||||
--> |
||||
<!ATTLIST set value-type CDATA #IMPLIED> |
||||
|
||||
|
||||
<!-- |
||||
A Spring map is a mapping from a string key to object. |
||||
Maps may be empty. |
||||
--> |
||||
<!ELEMENT map ( |
||||
(entry)* |
||||
)> |
||||
|
||||
<!-- |
||||
Enable/disable merging for collections when using parent/child beans. |
||||
--> |
||||
<!ATTLIST map merge (true | false | default) "default"> |
||||
|
||||
<!-- |
||||
Specify the default Java type for nested entry keys. |
||||
--> |
||||
<!ATTLIST map key-type CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
Specify the default Java type for nested entry values. |
||||
--> |
||||
<!ATTLIST map value-type CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
A map entry can be an inner bean, ref, value, or collection. |
||||
The key of the entry is given by the "key" attribute or child element. |
||||
--> |
||||
<!ELEMENT entry ( |
||||
key?, |
||||
(bean | ref | idref | value | null | list | set | map | props)? |
||||
)> |
||||
|
||||
<!-- |
||||
Each map element must specify its key as attribute or as child element. |
||||
A key attribute is always a String value. |
||||
--> |
||||
<!ATTLIST entry key CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
A short-cut alternative to a "key" element with a "ref bean=" child element. |
||||
--> |
||||
<!ATTLIST entry key-ref CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
A short-cut alternative to a child element "value". |
||||
--> |
||||
<!ATTLIST entry value CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
A short-cut alternative to a child element "ref bean=". |
||||
--> |
||||
<!ATTLIST entry value-ref CDATA #IMPLIED> |
||||
|
||||
<!-- |
||||
A key element can contain an inner bean, ref, value, or collection. |
||||
--> |
||||
<!ELEMENT key ( |
||||
(bean | ref | idref | value | null | list | set | map | props) |
||||
)> |
||||
|
||||
|
||||
<!-- |
||||
Props elements differ from map elements in that values must be strings. |
||||
Props may be empty. |
||||
--> |
||||
<!ELEMENT props ( |
||||
(prop)* |
||||
)> |
||||
|
||||
<!-- |
||||
Enable/disable merging for collections when using parent/child beans. |
||||
--> |
||||
<!ATTLIST props merge (true | false | default) "default"> |
||||
|
||||
<!-- |
||||
Element content is the string value of the property. |
||||
Note that whitespace is trimmed off to avoid unwanted whitespace |
||||
caused by typical XML formatting. |
||||
--> |
||||
<!ELEMENT prop (#PCDATA)> |
||||
|
||||
<!-- |
||||
Each property element must specify its key. |
||||
--> |
||||
<!ATTLIST prop key CDATA #REQUIRED></programlisting></para> |
||||
</appendix> |
||||
@ -0,0 +1,432 @@
@@ -0,0 +1,432 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<chapter id="ejb"> |
||||
<title>Enterprise Java Beans (EJB) integration</title> |
||||
|
||||
<section id="ejb-introduction"> |
||||
<title>Introduction</title> |
||||
<para> |
||||
As a lightweight container, Spring is often considered an EJB |
||||
replacement. We do believe that for many if not most applications and use |
||||
cases, Spring as a container, combined with its rich supporting |
||||
functionality in the area of transactions, ORM and JDBC access, is a better |
||||
choice than implementing equivalent functionality via an EJB container and |
||||
EJBs. |
||||
</para> |
||||
<para> |
||||
However, it is important to note that using Spring does not prevent |
||||
you from using EJBs. In fact, Spring makes it much easier to access EJBs and |
||||
implement EJBs and functionality within them. Additionally, using Spring to |
||||
access services provided by EJBs allows the implementation of those services |
||||
to later transparently be switched between local EJB, remote EJB, or POJO |
||||
(plain old Java object) variants, without the client code having to |
||||
be changed. |
||||
</para> |
||||
<para> |
||||
In this chapter, we look at how Spring can help you access and |
||||
implement EJBs. Spring provides particular value when accessing stateless |
||||
session beans (SLSBs), so we'll begin by discussing this. |
||||
</para> |
||||
</section> |
||||
|
||||
<section id="ejb-access"> |
||||
<title>Accessing EJBs</title> |
||||
|
||||
<section id="ejb-access-concepts"> |
||||
<title>Concepts</title> |
||||
<para> |
||||
To invoke a method on a local or remote stateless session bean, |
||||
client code must normally perform a JNDI lookup to obtain the (local or |
||||
remote) EJB Home object, then use a 'create' method call on that object |
||||
to obtain the actual (local or remote) EJB object. One or more methods |
||||
are then invoked on the EJB. |
||||
</para> |
||||
<para> |
||||
To avoid repeated low-level code, many EJB applications use the |
||||
Service Locator and Business Delegate patterns. These are better than |
||||
spraying JNDI lookups throughout client code, but their usual |
||||
implementations have significant disadvantages. For example: |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para> |
||||
Typically code using EJBs depends on Service Locator or |
||||
Business Delegate singletons, making it hard to test. |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
In the case of the Service Locator pattern used without a |
||||
Business Delegate, application code still ends up having to invoke |
||||
the create() method on an EJB home, and deal with the resulting |
||||
exceptions. Thus it remains tied to the EJB API and the complexity |
||||
of the EJB programming model. |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
Implementing the Business Delegate pattern typically results |
||||
in significant code duplication, where we have to write numerous |
||||
methods that simply call the same method on the EJB. |
||||
</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
<para> |
||||
The Spring approach is to allow the creation and use of proxy objects, |
||||
normally configured inside a Spring container, which act as codeless |
||||
business delegates. You do not need to write another Service Locator, another |
||||
JNDI lookup, or duplicate methods in a hand-coded Business Delegate unless |
||||
you are actually adding real value in such code. |
||||
</para> |
||||
</section> |
||||
|
||||
<section id="ejb-access-local"> |
||||
<title>Accessing local SLSBs</title> |
||||
<para> |
||||
Assume that we have a web controller that needs to use a local |
||||
EJB. We’ll follow best practice and use the EJB Business Methods |
||||
Interface pattern, so that the EJB’s local interface extends a non |
||||
EJB-specific business methods interface. Let’s call this business |
||||
methods interface <classname>MyComponent</classname>. |
||||
</para> |
||||
<programlisting><![CDATA[public interface MyComponent { |
||||
... |
||||
}]]></programlisting> |
||||
<para> |
||||
One of the main reasons to use the Business Methods Interface pattern |
||||
is to ensure that synchronization between method signatures in local |
||||
interface and bean implementation class is automatic. Another reason is |
||||
that it later makes it much easier for us to switch to a POJO (plain old |
||||
Java object) implementation of the service if it makes sense to do so. |
||||
Of course we’ll also need to implement the local home interface and |
||||
provide an implementation class that implements <classname>SessionBean</classname> |
||||
and the <classname>MyComponent</classname> business methods interface. Now the |
||||
only Java coding we’ll need to do to hook up our web tier controller to the |
||||
EJB implementation is to expose a setter method of type <classname>MyComponent</classname> |
||||
on the controller. This will save the reference as an instance variable in the |
||||
controller: |
||||
</para> |
||||
<programlisting><![CDATA[private MyComponent myComponent; |
||||
|
||||
public void setMyComponent(MyComponent myComponent) { |
||||
this.myComponent = myComponent; |
||||
}]]></programlisting> |
||||
<para> |
||||
We can subsequently use this instance variable in any business |
||||
method in the controller. Now assuming we are obtaining our controller |
||||
object out of a Spring container, we can (in the same context) configure a |
||||
<classname>LocalStatelessSessionProxyFactoryBean</classname> instance, which |
||||
will be the EJB proxy object. The configuration of the proxy, and setting of |
||||
the <literal>myComponent</literal> property of the controller is done |
||||
with a configuration entry such as: |
||||
</para> |
||||
<programlisting><![CDATA[<bean id="myComponent" |
||||
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean"> |
||||
<property name="jndiName" value="ejb/myBean"/> |
||||
<property name="businessInterface" value="com.mycom.MyComponent"/> |
||||
</bean> |
||||
|
||||
<bean id="myController" class="com.mycom.myController"> |
||||
<property name="myComponent" ref="myComponent"/> |
||||
</bean>]]></programlisting> |
||||
<para> |
||||
There’s a lot of work happening behind the scenes, courtesy of |
||||
the Spring AOP framework, although you aren’t forced to work with AOP |
||||
concepts to enjoy the results. The <literal>myComponent</literal> bean |
||||
definition creates a proxy for the EJB, which implements the business |
||||
method interface. The EJB local home is cached on startup, so there’s |
||||
only a single JNDI lookup. Each time the EJB is invoked, the proxy |
||||
invokes the <literal>classname</literal> method on the local EJB and |
||||
invokes the corresponding business method on the EJB. |
||||
</para> |
||||
<para> |
||||
The <literal>myController</literal> bean definition sets the |
||||
<literal>myComponent</literal> property of the controller class to the |
||||
EJB proxy. |
||||
</para> |
||||
<para> |
||||
Alternatively (and preferably in case of many such proxy definitions), |
||||
consider using the <literal><jee:local-slsb></literal> |
||||
configuration element in Spring's "jee" namespace: |
||||
</para> |
||||
<programlisting><![CDATA[<jee:local-slsb id="myComponent" jndi-name="ejb/myBean" |
||||
business-interface="com.mycom.MyComponent"/> |
||||
|
||||
<bean id="myController" class="com.mycom.myController"> |
||||
<property name="myComponent" ref="myComponent"/> |
||||
</bean>]]></programlisting> |
||||
<para> |
||||
This EJB access mechanism delivers huge simplification of |
||||
application code: the web tier code (or other EJB client code) has no |
||||
dependence on the use of EJB. If we want to replace this EJB reference |
||||
with a POJO or a mock object or other test stub, we could simply change |
||||
the <literal>myComponent</literal> bean definition without changing a |
||||
line of Java code. Additionally, we haven’t had to write a single line of |
||||
JNDI lookup or other EJB plumbing code as part of our application. |
||||
</para> |
||||
<para> |
||||
Benchmarks and experience in real applications indicate that the |
||||
performance overhead of this approach (which involves reflective |
||||
invocation of the target EJB) is minimal, and is typically undetectable |
||||
in typical use. Remember that we don’t want to make fine-grained calls |
||||
to EJBs anyway, as there’s a cost associated with the EJB infrastructure |
||||
in the application server. |
||||
</para> |
||||
<para> |
||||
There is one caveat with regards to the JNDI lookup. In a bean |
||||
container, this class is normally best used as a singleton (there simply |
||||
is no reason to make it a prototype). However, if that bean container |
||||
pre-instantiates singletons (as do the various XML |
||||
<classname>ApplicationContext</classname> variants) |
||||
you may have a problem if the bean container is loaded before the EJB |
||||
container loads the target EJB. That is because the JNDI lookup will be |
||||
performed in the <literal>init()</literal> method of this class and then |
||||
cached, but the EJB will not have been bound at the target location yet. |
||||
The solution is to not pre-instantiate this factory object, but allow it |
||||
to be created on first use. In the XML containers, this is controlled via |
||||
the <literal>lazy-init</literal> attribute. |
||||
</para> |
||||
<para> |
||||
Although this will not be of interest to the majority of Spring |
||||
users, those doing programmatic AOP work with EJBs may want to look at |
||||
<classname>LocalSlsbInvokerInterceptor</classname>. |
||||
</para> |
||||
</section> |
||||
|
||||
<section id="ejb-access-remote"> |
||||
<title>Accessing remote SLSBs</title> |
||||
<para> |
||||
Accessing remote EJBs is essentially identical to accessing local |
||||
EJBs, except that the |
||||
<classname>SimpleRemoteStatelessSessionProxyFactoryBean</classname> or |
||||
<literal><jee:remote-slsb></literal> configuration element is used. |
||||
Of course, with or without Spring, remote invocation semantics apply; a |
||||
call to a method on an object in another VM in another computer does |
||||
sometimes have to be treated differently in terms of usage scenarios and |
||||
failure handling. |
||||
</para> |
||||
<para> |
||||
Spring's EJB client support adds one more advantage over the |
||||
non-Spring approach. Normally it is problematic for EJB client code to |
||||
be easily switched back and forth between calling EJBs locally or |
||||
remotely. This is because the remote interface methods must declare that |
||||
they throw <classname>RemoteException</classname>, and client code must deal |
||||
with this, while the local interface methods don't. Client code |
||||
written for local EJBs which needs to be moved to remote EJBs |
||||
typically has to be modified to add handling for the remote exceptions, |
||||
and client code written for remote EJBs which needs to be moved to local |
||||
EJBs, can either stay the same but do a lot of unnecessary handling of |
||||
remote exceptions, or needs to be modified to remove that code. With the |
||||
Spring remote EJB proxy, you can instead not declare any thrown |
||||
<classname>RemoteException</classname> in your Business Method Interface and |
||||
implementing EJB code, have a remote interface which is identical except |
||||
that it does throw <classname>RemoteException</classname>, and rely on the |
||||
proxy to dynamically treat the two interfaces as if they were the same. |
||||
That is, client code does not have to deal with the checked |
||||
<classname>RemoteException</classname> class. Any actual |
||||
<classname>RemoteException</classname> that is thrown during the EJB |
||||
invocation will be re-thrown as the non-checked |
||||
<classname>RemoteAccessException</classname> class, which is a subclass of |
||||
<classname>RuntimeException</classname>. The target service can then be |
||||
switched at will between a local EJB or remote EJB (or even plain Java |
||||
object) implementation, without the client code knowing or caring. Of |
||||
course, this is optional; there is nothing stopping you from declaring |
||||
<classname>RemoteExceptions</classname> in your business interface. |
||||
</para> |
||||
</section> |
||||
|
||||
<section id="ejb-access-ejb2-ejb3"> |
||||
<title>Accessing EJB 2.x SLSBs versus EJB 3 SLSBs</title> |
||||
<para> |
||||
Accessing EJB 2.x Session Beans and EJB 3 Session Beans via Spring |
||||
is largely transparent. Spring's EJB accessors, including the |
||||
<literal><jee:local-slsb></literal> and <literal><jee:remote-slsb></literal> |
||||
facilities, transparently adapt to the actual component at runtime. |
||||
They handle a home interface if found (EJB 2.x style), or perform straight |
||||
component invocations if no home interface is available (EJB 3 style). |
||||
</para> |
||||
<para> |
||||
Note: For EJB 3 Session Beans, you could effectively use a |
||||
<classname>JndiObjectFactoryBean</classname> / <literal><jee:jndi-lookup></literal> |
||||
as well, since fully usable component references are exposed for plain |
||||
JNDI lookups there. Defining explicit <literal><jee:local-slsb></literal> |
||||
/ <literal><jee:remote-slsb></literal> lookups simply provides |
||||
consistent and more explicit EJB access configuration. |
||||
</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="ejb-implementation"> |
||||
<title>Using Spring's EJB implementation support classes</title> |
||||
|
||||
<section id="ejb-implementation-ejb2"> |
||||
<title>EJB 2.x base classes</title> |
||||
<para> |
||||
Spring provides convenience classes to help you implement EJBs. |
||||
These are designed to encourage the good practice of putting business |
||||
logic behind EJBs in POJOs, leaving EJBs responsible for transaction |
||||
demarcation and (optionally) remoting. |
||||
</para> |
||||
<para> |
||||
To implement a Stateless or Stateful session bean, or a Message Driven |
||||
bean, you need only derive your implementation class from |
||||
<classname>AbstractStatelessSessionBean</classname>, |
||||
<classname>AbstractStatefulSessionBean</classname>, and |
||||
<classname>AbstractMessageDrivenBean</classname>/<classname>AbstractJmsMessageDrivenBean</classname>, |
||||
respectively. |
||||
</para> |
||||
<para> |
||||
Consider an example Stateless Session bean which actually delegates |
||||
the implementation to a plain java service object. We have the business interface: |
||||
</para> |
||||
<programlisting><![CDATA[public interface MyComponent { |
||||
public void myMethod(...); |
||||
... |
||||
}]]></programlisting> |
||||
<para>We also have the plain Java implementation object:</para> |
||||
<programlisting><![CDATA[public class MyComponentImpl implements MyComponent { |
||||
public String myMethod(...) { |
||||
... |
||||
} |
||||
... |
||||
}]]></programlisting> |
||||
<para>And finally the Stateless Session Bean itself:</para> |
||||
<programlisting><![CDATA[public class MyFacadeEJB extends AbstractStatelessSessionBean |
||||
implements MyFacadeLocal { |
||||
|
||||
private MyComponent myComp; |
||||
|
||||
/** |
||||
* Obtain our POJO service object from the BeanFactory/ApplicationContext |
||||
* @see org.springframework.ejb.support.AbstractStatelessSessionBean#onEjbCreate() |
||||
*/ |
||||
protected void onEjbCreate() throws CreateException { |
||||
myComp = (MyComponent) getBeanFactory().getBean( |
||||
ServicesConstants.CONTEXT_MYCOMP_ID); |
||||
} |
||||
|
||||
// for business method, delegate to POJO service impl. |
||||
public String myFacadeMethod(...) { |
||||
return myComp.myMethod(...); |
||||
} |
||||
... |
||||
}]]></programlisting> |
||||
<para> |
||||
The Spring EJB support base classes will by default create and load |
||||
a Spring IoC container as part of their lifecycle, which is then available |
||||
to the EJB (for example, as used in the code above to obtain the POJO |
||||
service object). The loading is done via a strategy object which is a subclass of |
||||
<classname>BeanFactoryLocator</classname>. The actual implementation of |
||||
<classname>BeanFactoryLocator</classname> used by default is |
||||
<classname>ContextJndiBeanFactoryLocator</classname>, which creates the |
||||
ApplicationContext from a resource locations specified as a JNDI |
||||
environment variable (in the case of the EJB classes, at |
||||
<literal>java:comp/env/ejb/BeanFactoryPath</literal>). If there is a need |
||||
to change the BeanFactory/ApplicationContext loading strategy, the default |
||||
<classname>BeanFactoryLocator</classname> implementation used may be overridden |
||||
by calling the <literal>setBeanFactoryLocator()</literal> method, either |
||||
in <literal>setSessionContext()</literal>, or in the actual constructor of |
||||
the EJB. Please see the Javadocs for more details. |
||||
</para> |
||||
<para> |
||||
As described in the Javadocs, Stateful Session beans expecting to be |
||||
passivated and reactivated as part of their lifecycle, and which use a |
||||
non-serializable container instance (which is the normal case) will have |
||||
to manually call <literal>unloadBeanFactory()</literal> and |
||||
<literal>loadBeanFactory</literal> from <literal>ejbPassivate</literal> |
||||
and <literal>ejbActivate</literal>, respectively, to unload and reload the |
||||
BeanFactory on passivation and activation, since it can not be saved by |
||||
the EJB container. |
||||
</para> |
||||
<para> |
||||
The default behavior of the <classname>ContextJndiBeanFactoryLocator</classname> |
||||
classes which is to load an <classname>ApplicationContext</classname> for the |
||||
use of the EJB is adequate for some situations. However, it is problematic when |
||||
the <classname>ApplicationContext</classname> is loading a number |
||||
of beans, or the initialization of those beans is time consuming or memory |
||||
intensive (such as a Hibernate <classname>SessionFactory</classname> initialization, for |
||||
example), since every EJB will have their own copy. In this case, the user |
||||
may want to override the default <classname>ContextJndiBeanFactoryLocator</classname> |
||||
usage and use another <classname>BeanFactoryLocator</classname> variant, such as the |
||||
<classname>ContextSingletonBeanFactoryLocator</classname> which can load and use a |
||||
shared container to be used by multiple EJBs or other clients. Doing this is relatively |
||||
simple, by adding code similar to this to the EJB: |
||||
</para> |
||||
<programlisting><![CDATA[ /** |
||||
* Override default BeanFactoryLocator implementation |
||||
* @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext) |
||||
*/ |
||||
public void setSessionContext(SessionContext sessionContext) { |
||||
super.setSessionContext(sessionContext); |
||||
setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance()); |
||||
setBeanFactoryLocatorKey(ServicesConstants.PRIMARY_CONTEXT_ID); |
||||
}]]></programlisting> |
||||
<para> |
||||
You would then need to create a bean definition file named <literal>beanRefContext.xml</literal>. |
||||
This file defines all bean factories (usually in the form of application contexts) that may be used |
||||
in the EJB. In many cases, this file will only contain a single bean definition such as this (where |
||||
<literal>businessApplicationContext.xml</literal> contains the bean definitions for all business |
||||
service POJOs): |
||||
</para> |
||||
<programlisting><![CDATA[<beans> |
||||
<bean id="businessBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext"> |
||||
<constructor-arg value="businessApplicationContext.xml" /> |
||||
</bean> |
||||
</beans>]]></programlisting> |
||||
<para> |
||||
In the above example, the <literal>ServicesConstants.PRIMARY_CONTEXT_ID</literal> constant |
||||
would be defined as follows: |
||||
</para> |
||||
<programlisting><![CDATA[public static final String ServicesConstants.PRIMARY_CONTEXT_ID = "businessBeanFactory";]]></programlisting> |
||||
<para> |
||||
Please see the respective Javadocs for the <classname>BeanFactoryLocator</classname> and |
||||
<classname>ContextSingletonBeanFactoryLocator</classname> classes for more information on |
||||
their usage. |
||||
</para> |
||||
</section> |
||||
|
||||
<section id="ejb-implementation-ejb3"> |
||||
<title>EJB 3 injection interceptor</title> |
||||
<para> |
||||
For EJB 3 Session Beans and Message-Driven Beans, Spring provides a convenient |
||||
interceptor that resolves Spring 2.5's <literal>@Autowired</literal> annotation |
||||
in the EJB component class: |
||||
<classname>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</classname>. |
||||
This interceptor can be applied through an <code>@Interceptors</code> annotation |
||||
in the EJB component class, or through an <literal>interceptor-binding</literal> |
||||
XML element in the EJB deployment descriptor. |
||||
</para> |
||||
<programlisting><![CDATA[@Stateless |
||||
@Interceptors(SpringBeanAutowiringInterceptor.class) |
||||
public class MyFacadeEJB implements MyFacadeLocal { |
||||
|
||||
// automatically injected with a matching Spring bean |
||||
@Autowired |
||||
private MyComponent myComp; |
||||
|
||||
// for business method, delegate to POJO service impl. |
||||
public String myFacadeMethod(...) { |
||||
return myComp.myMethod(...); |
||||
} |
||||
... |
||||
}]]></programlisting> |
||||
<para> |
||||
<classname>SpringBeanAutowiringInterceptor</classname> by default obtains target |
||||
beans from a <classname>ContextSingletonBeanFactoryLocator</classname>, with the |
||||
context defined in a bean definition file named <literal>beanRefContext.xml</literal>. |
||||
By default, a single context definition is expected, which is obtained by type rather |
||||
than by name. However, if you need to choose between multiple context definitions, |
||||
a specific locator key is required. The locator key (i.e. the name of the context |
||||
definition in <literal>beanRefContext.xml</literal>) can be explicitly specified |
||||
either through overriding the <literal>getBeanFactoryLocatorKey</literal> method |
||||
in a custom <classname>SpringBeanAutowiringInterceptor</classname> subclass. |
||||
</para> |
||||
<para> |
||||
Alternatively, consider overriding <classname>SpringBeanAutowiringInterceptor</classname>'s |
||||
<literal>getBeanFactory</literal> method, e.g. obtaining a shared |
||||
<interfacename>ApplicationContext</interfacename> from a custom holder class. |
||||
</para> |
||||
</section> |
||||
|
||||
</section> |
||||
|
||||
</chapter> |
||||
@ -0,0 +1,403 @@
@@ -0,0 +1,403 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<chapter id="mail"> |
||||
<title>Email</title> |
||||
|
||||
<section id="mail-introduction"> |
||||
<title>Introduction</title> |
||||
<sidebar> |
||||
<title>Library dependencies</title> |
||||
<para>The following additional jars to be on the classpath of your |
||||
application in order to be able to use the Spring Framework's email library.</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>The <ulink url="http://java.sun.com/products/javamail/">JavaMail</ulink> <filename class="libraryfile">mail.jar</filename> library</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para>The <ulink url="http://java.sun.com/products/javabeans/jaf/downloads/index.html">JAF</ulink> <filename class="libraryfile">activation.jar</filename> library</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
<para>All of these libraries are available in the Spring-with-dependencies |
||||
distribution of the Spring Framework (in addition to also being freely |
||||
available on the web).</para> |
||||
</sidebar> |
||||
|
||||
<para>The Spring Framework provides a helpful utility library for sending |
||||
email that shields the user from the specifics of the underlying mailing |
||||
system and is responsible for low level resource handling on behalf of |
||||
the client.</para> |
||||
|
||||
<para>The <literal>org.springframework.mail</literal> package is the root level package |
||||
for the Spring Framework's email support. The central interface for sending |
||||
emails is the <interfacename>MailSender</interfacename> interface; a simple value object |
||||
encapsulating the properties of a simple mail such as <emphasis>from</emphasis> and |
||||
<emphasis>to</emphasis> (plus many others) is the <classname>SimpleMailMessage</classname> class. |
||||
This package also contains a hierarchy of checked exceptions which provide |
||||
a higher level of abstraction over the lower level mail system exceptions |
||||
with the root exception being <exceptionname>MailException</exceptionname>. Please |
||||
refer to the Javadocs for more information on the rich mail exception hierarchy.</para> |
||||
|
||||
<para>The <interfacename>org.springframework.mail.javamail.JavaMailSender</interfacename> |
||||
interface adds specialized <emphasis>JavaMail</emphasis> features such as MIME |
||||
message support to the <interfacename>MailSender</interfacename> interface |
||||
(from which it inherits). <interfacename>JavaMailSender</interfacename> also provides a |
||||
callback interface for preparation of JavaMail MIME messages, called |
||||
<interfacename>org.springframework.mail.javamail.MimeMessagePreparator</interfacename></para> |
||||
|
||||
</section> |
||||
|
||||
<section id="mail-usage"> |
||||
<title>Usage</title> |
||||
<para>Let's assume there is a business interface called <interfacename>OrderManager</interfacename>:</para> |
||||
<programlisting><![CDATA[public interface OrderManager { |
||||
|
||||
void placeOrder(Order order); |
||||
}]]></programlisting> |
||||
|
||||
<para>Let us also assume that there is a requirement stating that an email message |
||||
with an order number needs to be generated and sent to a customer placing the |
||||
relevant order.</para> |
||||
|
||||
<section id="mail-usage-simple"> |
||||
<title>Basic <interfacename>MailSender</interfacename> and <classname>SimpleMailMessage</classname> usage</title> |
||||
<programlisting><![CDATA[import org.springframework.mail.MailException; |
||||
import org.springframework.mail.MailSender; |
||||
import org.springframework.mail.SimpleMailMessage; |
||||
|
||||
public class SimpleOrderManager implements OrderManager { |
||||
|
||||
private MailSender mailSender; |
||||
private SimpleMailMessage templateMessage; |
||||
|
||||
public void setMailSender(MailSender mailSender) { |
||||
this.mailSender = mailSender; |
||||
} |
||||
|
||||
public void setTemplateMessage(SimpleMailMessage templateMessage) { |
||||
this.templateMessage = templateMessage; |
||||
} |
||||
|
||||
public void placeOrder(Order order) { |
||||
|
||||
]]><lineannotation>// Do the business calculations...</lineannotation><![CDATA[ |
||||
|
||||
]]><lineannotation>// Call the collaborators to persist the order...</lineannotation><![CDATA[ |
||||
|
||||
]]><lineannotation>// Create a thread safe "copy" of the template message and customize it</lineannotation><![CDATA[ |
||||
SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); |
||||
msg.setTo(order.getCustomer().getEmailAddress()); |
||||
msg.setText( |
||||
"Dear " + order.getCustomer().getFirstName() |
||||
+ order.getCustomer().getLastName() |
||||
+ ", thank you for placing order. Your order number is " |
||||
+ order.getOrderNumber()); |
||||
try{ |
||||
this.mailSender.send(msg); |
||||
} |
||||
catch(MailException ex) { |
||||
]]><lineannotation>// simply log it and go on...</lineannotation><![CDATA[ |
||||
System.err.println(ex.getMessage()); |
||||
} |
||||
} |
||||
}]]></programlisting> |
||||
|
||||
<para>Find below the bean definitions for the above code:</para> |
||||
<programlisting><![CDATA[<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> |
||||
<property name="host" value="mail.mycompany.com"/> |
||||
</bean> |
||||
|
||||
]]><lineannotation><!-- this is a template message that we can pre-load with default state --></lineannotation><![CDATA[ |
||||
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage"> |
||||
<property name="from" value="customerservice@mycompany.com"/> |
||||
<property name="subject" value="Your order"/> |
||||
</bean> |
||||
|
||||
<bean id="orderManager" class="com.mycompany.businessapp.support.SimpleOrderManager"> |
||||
<property name="mailSender" ref="mailSender"/> |
||||
<property name="templateMessage" ref="templateMessage"/> |
||||
</bean>]]></programlisting> |
||||
|
||||
</section> |
||||
|
||||
<section id="mail-usage-mime"> |
||||
<title>Using the <interfacename>JavaMailSender</interfacename> and the <classname>MimeMessagePreparator</classname></title> |
||||
<para>Here is another implementation of <interfacename>OrderManager</interfacename> using |
||||
the <interfacename>MimeMessagePreparator</interfacename> callback interface. Please note |
||||
in this case that the <literal>mailSender</literal> property is of type |
||||
<interfacename>JavaMailSender</interfacename> so that we are able to use the JavaMail |
||||
<classname>MimeMessage</classname> class:</para> |
||||
|
||||
<programlisting><![CDATA[import javax.mail.Message; |
||||
import javax.mail.MessagingException; |
||||
import javax.mail.internet.InternetAddress; |
||||
import javax.mail.internet.MimeMessage; |
||||
|
||||
import javax.mail.internet.MimeMessage; |
||||
import org.springframework.mail.MailException; |
||||
import org.springframework.mail.javamail.JavaMailSender; |
||||
import org.springframework.mail.javamail.MimeMessagePreparator; |
||||
|
||||
public class SimpleOrderManager implements OrderManager { |
||||
|
||||
private JavaMailSender mailSender; |
||||
|
||||
public void setMailSender(JavaMailSender mailSender) { |
||||
this.mailSender = mailSender; |
||||
} |
||||
|
||||
public void placeOrder(final Order order) { |
||||
|
||||
]]><lineannotation>// Do the business calculations...</lineannotation><![CDATA[ |
||||
|
||||
]]><lineannotation>// Call the collaborators to persist the order...</lineannotation><![CDATA[ |
||||
|
||||
MimeMessagePreparator preparator = new MimeMessagePreparator() { |
||||
|
||||
public void prepare(MimeMessage mimeMessage) throws Exception { |
||||
|
||||
mimeMessage.setRecipient(Message.RecipientType.TO, |
||||
new InternetAddress(order.getCustomer().getEmailAddress())); |
||||
mimeMessage.setFrom(new InternetAddress("mail@mycompany.com")); |
||||
mimeMessage.setText( |
||||
"Dear " + order.getCustomer().getFirstName() + " " |
||||
+ order.getCustomer().getLastName() |
||||
+ ", thank you for placing order. Your order number is " |
||||
+ order.getOrderNumber()); |
||||
} |
||||
}; |
||||
try { |
||||
this.mailSender.send(preparator); |
||||
} |
||||
catch (MailException ex) { |
||||
]]><lineannotation>// simply log it and go on...</lineannotation><![CDATA[ |
||||
System.err.println(ex.getMessage()); |
||||
} |
||||
} |
||||
}]]></programlisting> |
||||
|
||||
<note> |
||||
<para>The mail code is a crosscutting concern and could well be a candidate |
||||
for refactoring into a <link linkend="aop">custom Spring AOP aspect</link>, |
||||
which then could be executed at appropriate joinpoints on the |
||||
<interfacename>OrderManager</interfacename> target.</para> |
||||
</note> |
||||
|
||||
<para>The Spring Framework's mail support ships with two |
||||
<interfacename>MailSender</interfacename> implementations. The standard JavaMail |
||||
implementation and the implementation on top of Jason Hunter's |
||||
<classname>MailMessage</classname> class that is included in |
||||
<ulink url="http://servlets.com/cos">the <literal>com.oreilly.servlet</literal> |
||||
package</ulink>. Please refer to the relevant Javadocs for more information.</para> |
||||
</section> |
||||
|
||||
</section> |
||||
|
||||
<section id="mail-javamail-mime"> |
||||
<title>Using the JavaMail <classname>MimeMessageHelper</classname></title> |
||||
|
||||
<para>A class that comes in pretty handy when dealing with JavaMail messages is |
||||
the <classname>org.springframework.mail.javamail.MimeMessageHelper</classname> class, |
||||
which shields you from having to use the verbose JavaMail API. Using |
||||
the <classname>MimeMessageHelper</classname> it is pretty easy to |
||||
create a <classname>MimeMessage</classname>:</para> |
||||
<programlisting><lineannotation>// of course you would use DI in any real-world cases</lineannotation><![CDATA[ |
||||
JavaMailSenderImpl sender = new JavaMailSenderImpl(); |
||||
sender.setHost("mail.host.com"); |
||||
|
||||
MimeMessage message = sender.createMimeMessage(); |
||||
MimeMessageHelper helper = new MimeMessageHelper(message); |
||||
helper.setTo("test@host.com"); |
||||
helper.setText("Thank you for ordering!"); |
||||
|
||||
sender.send(message);]]></programlisting> |
||||
|
||||
<section id="mail-javamail-mime-attachments"> |
||||
<title>Sending attachments and inline resources</title> |
||||
<para>Multipart email messages allow for both attachments and inline resources. |
||||
Examples of inline resources would be be images or a stylesheet you want to use |
||||
in your message, but that you don't want displayed as an attachment.</para> |
||||
<section id="mail-javamail-mime-attachments-attachment"> |
||||
<title>Attachments</title> |
||||
<para>The following example shows you how to use the |
||||
<classname>MimeMessageHelper</classname> to send an email along with a |
||||
single JPEG image attachment.</para> |
||||
<programlisting><![CDATA[JavaMailSenderImpl sender = new JavaMailSenderImpl(); |
||||
sender.setHost("mail.host.com"); |
||||
|
||||
MimeMessage message = sender.createMimeMessage(); |
||||
|
||||
]]><lineannotation>// use the true flag to indicate you need a multipart message</lineannotation><![CDATA[ |
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true); |
||||
helper.setTo("test@host.com"); |
||||
|
||||
helper.setText("Check out this image!"); |
||||
|
||||
]]><lineannotation>// let's attach the infamous windows Sample file (this time copied to c:/)</lineannotation><![CDATA[ |
||||
FileSystemResource file = new FileSystemResource(new File("c:/Sample.jpg")); |
||||
helper.addAttachment("CoolImage.jpg", file); |
||||
|
||||
sender.send(message);]]></programlisting> |
||||
</section> |
||||
<section id="mail-javamail-mime-attachments-inline"> |
||||
<title>Inline resources</title> |
||||
<para>The following example shows you how to use the |
||||
<classname>MimeMessageHelper</classname> to send an email along with an |
||||
inline image.</para> |
||||
<programlisting><![CDATA[JavaMailSenderImpl sender = new JavaMailSenderImpl(); |
||||
sender.setHost("mail.host.com"); |
||||
|
||||
MimeMessage message = sender.createMimeMessage(); |
||||
|
||||
]]><lineannotation>// use the true flag to indicate you need a multipart message</lineannotation><![CDATA[ |
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true); |
||||
helper.setTo("test@host.com"); |
||||
|
||||
]]><lineannotation>// use the true flag to indicate the text included is HTML</lineannotation><![CDATA[ |
||||
helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true); |
||||
|
||||
]]><lineannotation>// let's include the infamous windows Sample file (this time copied to c:/)</lineannotation><![CDATA[ |
||||
FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg")); |
||||
helper.addInline("identifier1234", res); |
||||
|
||||
sender.send(message);]]></programlisting> |
||||
<warning> |
||||
<para>Inline resources are added to the mime message using the |
||||
specified <literal>Content-ID</literal> (<literal>identifier1234</literal> |
||||
in the above example). The order in which you are adding the text and the |
||||
resource are <emphasis role="bold">very</emphasis> important. Be sure to |
||||
<emphasis>first add the text</emphasis> and after that the resources. If |
||||
you are doing it the other way around, it won't work!</para> |
||||
</warning> |
||||
</section> |
||||
</section> |
||||
<section id="mail-templates"> |
||||
<title>Creating email content using a templating library</title> |
||||
<para>The code in the previous examples explicitly has been creating the |
||||
content of the email message, using methods calls such as |
||||
<methodname>message.setText(..)</methodname>. This is fine for |
||||
simple cases, and it is okay in the context of the aforementioned |
||||
examples, where the intent was to show you the very basics of the API.</para> |
||||
<para>In your typical enterprise application though, you are not going |
||||
to create the content of your emails using the above approach for a number |
||||
of reasons.</para> |
||||
<para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>Creating HTML-based email content in Java code is tedious and error prone</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para>There is no clear separation between display logic and business logic</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para>Changing the display structure of the email content requires writing Java code, recompiling, redeploying...</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</para> |
||||
<para>Typically the approach taken to address these issues is to use a template library |
||||
such as FreeMarker or Velocity to define the display structure of email content. This leaves |
||||
your code tasked only with creating the data that is to be rendered in the email |
||||
template and sending the email. It is definitely a best practice for when |
||||
the content of your emails becomes even moderately complex, and with |
||||
the Spring Framework's support classes for FreeMarker and Velocity becomes |
||||
quite easy to do. Find below an example of using the Velocity template library |
||||
to create email content.</para> |
||||
<section id="mail-templates-example"> |
||||
<title>A Velocity-based example</title> |
||||
<para>To use <ulink url="http://velocity.apache.org">Velocity</ulink> to |
||||
create your email template(s), you will need to have the Velocity libraries |
||||
available on your classpath. You will also need to create one or more Velocity templates |
||||
for the email content that your application needs. Find below the Velocity |
||||
template that this example will be using... as you can see it is HTML-based, |
||||
and since it is plain text it can be created using your favorite HTML editor |
||||
without recourse to having to know Java.</para> |
||||
<programlisting><lineannotation># in the <literal>com/foo/package</literal></lineannotation><![CDATA[ |
||||
<html> |
||||
<body> |
||||
<h3>Hi ${user.userName}, welcome to the Chipping Sodbury On-the-Hill message boards!</h3> |
||||
|
||||
<div> |
||||
Your email address is <a href="mailto:${user.emailAddress}">${user.emailAddress}</a>. |
||||
</div> |
||||
</body> |
||||
|
||||
</html>]]></programlisting> |
||||
<para>Find below some simple code and Spring XML configuration that |
||||
makes use of the above Velocity template to create email content and |
||||
send email(s).</para> |
||||
<programlisting><![CDATA[package com.foo; |
||||
|
||||
import org.apache.velocity.app.VelocityEngine; |
||||
import org.springframework.mail.javamail.JavaMailSender; |
||||
import org.springframework.mail.javamail.MimeMessageHelper; |
||||
import org.springframework.mail.javamail.MimeMessagePreparator; |
||||
import org.springframework.ui.velocity.VelocityEngineUtils; |
||||
|
||||
import javax.mail.internet.MimeMessage; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public class SimpleRegistrationService implements RegistrationService { |
||||
|
||||
private JavaMailSender mailSender; |
||||
private VelocityEngine velocityEngine; |
||||
|
||||
public void setMailSender(JavaMailSender mailSender) { |
||||
this.mailSender = mailSender; |
||||
} |
||||
|
||||
public void setVelocityEngine(VelocityEngine velocityEngine) { |
||||
this.velocityEngine = velocityEngine; |
||||
} |
||||
|
||||
public void register(User user) { |
||||
|
||||
]]><lineannotation>// Do the registration logic...</lineannotation><![CDATA[ |
||||
|
||||
sendConfirmationEmail(user); |
||||
} |
||||
|
||||
private void sendConfirmationEmail(final User user) { |
||||
MimeMessagePreparator preparator = new MimeMessagePreparator() { |
||||
public void prepare(MimeMessage mimeMessage) throws Exception { |
||||
MimeMessageHelper message = new MimeMessageHelper(mimeMessage); |
||||
message.setTo(user.getEmailAddress()); |
||||
message.setFrom("webmaster@csonth.gov.uk"); ]]><lineannotation>// could be parameterized...</lineannotation><![CDATA[ |
||||
Map model = new HashMap(); |
||||
model.put("user", user); |
||||
String text = VelocityEngineUtils.mergeTemplateIntoString( |
||||
velocityEngine, "com/dns/registration-confirmation.vm", model); |
||||
message.setText(text, true); |
||||
} |
||||
}; |
||||
this.mailSender.send(preparator); |
||||
} |
||||
}]]></programlisting> |
||||
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?> |
||||
<beans xmlns="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans |
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> |
||||
|
||||
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> |
||||
<property name="host" value="mail.csonth.gov.uk"/> |
||||
</bean> |
||||
|
||||
<bean id="registrationService" class="com.foo.SimpleRegistrationService"> |
||||
<property name="mailSender" ref="mailSender"/> |
||||
<property name="velocityEngine" ref="velocityEngine"/> |
||||
</bean> |
||||
|
||||
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean"> |
||||
<property name="velocityProperties"> |
||||
<value> |
||||
resource.loader=class |
||||
class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader |
||||
</value> |
||||
</property> |
||||
</bean> |
||||
|
||||
</beans>]]></programlisting> |
||||
</section> |
||||
</section> |
||||
</section> |
||||
|
||||
</chapter> |
||||
@ -0,0 +1,503 @@
@@ -0,0 +1,503 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<chapter id="metadata"> |
||||
<title>Annotations and Source Level Metadata Support</title> |
||||
<section id="metadata-introduction"> |
||||
<title>Introduction</title> |
||||
<para>Source-level metadata is the addition of <emphasis>attributes</emphasis> or |
||||
<emphasis>annotations</emphasis> to program elements - usually, classes |
||||
and/or methods.</para> |
||||
<para>For example, we might add metadata to a class as follows:</para> |
||||
<programlisting><![CDATA[/** |
||||
* Normal comments here |
||||
* @@org.springframework.transaction.interceptor.DefaultTransactionAttribute() |
||||
*/ |
||||
public class PetStoreImpl implements PetStoreFacade, OrderService {]]></programlisting> |
||||
<para>We could add metadata to a method as follows:</para> |
||||
<programlisting><![CDATA[/** |
||||
* Normal comments here |
||||
* @@org.springframework.transaction.interceptor.RuleBasedTransactionAttribute() |
||||
* @@org.springframework.transaction.interceptor.RollbackRuleAttribute(Exception.class) |
||||
* @@org.springframework.transaction.interceptor.NoRollbackRuleAttribute("ServletException") |
||||
*/ |
||||
public void echoException(Exception ex) throws Exception { |
||||
.... |
||||
}]]></programlisting> |
||||
<para>Both of these examples use Jakarta Commons Attributes syntax.</para> |
||||
<para> |
||||
Source-level metadata was introduced to the mainstream by XDoclet |
||||
(in the Java world) and by the release of Microsoft's .NET platform, which |
||||
uses source-level attributes to control transactions, pooling and other |
||||
behavior. |
||||
</para> |
||||
<para> |
||||
The value in this approach has been recognized in the J2EE |
||||
community. For example, it's much less verbose than the traditional XML |
||||
deployment descriptors used exclusively by EJB. While it is desirable to |
||||
externalize some things from program source code, some important |
||||
enterprise settings - notably transaction characteristics - arguably belong |
||||
in program source. Contrary to the assumptions of the EJB spec, it seldom |
||||
makes sense to modify the transactional characteristics of a method |
||||
(although parameters like transaction timeouts might change!). |
||||
</para> |
||||
<para> |
||||
Although metadata attributes are typically used mainly by framework |
||||
infrastructure to describe the services application classes require, it |
||||
should also be possible for metadata attributes to be queried at runtime. |
||||
This is a key distinction from solutions such as XDoclet, which |
||||
view metadata primarily as a way of generating code such as EJB artefacts. |
||||
</para> |
||||
<para> |
||||
There are a number of solutions in this space, including: |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para><emphasis role="bold">Standard Java Annotations</emphasis>: the |
||||
standard Java metadata implementation (developed as JSR-175 and available |
||||
in Java 5). Spring has specific Java 5 annotations for transactional |
||||
demarcation, JMX, and aspects (to be precise they are AspectJ annotations). |
||||
However, since Spring supports Java 1.4 as well, a solution for said |
||||
JVM versions is needed too. Spring metadata support provides such a |
||||
solution.</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><emphasis role="bold">XDoclet</emphasis>: well-established |
||||
solution, primarily intended for code generation.</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para>Various <emphasis role="bold">open source attribute |
||||
implementations</emphasis>, for Java 1.4, of which Commons |
||||
Attributes is the most complete implementation. All these require |
||||
a special pre- or post-compilation step.</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</section> |
||||
<section id="metadata-spring"> |
||||
<title>Spring's metadata support</title> |
||||
<para>In keeping with its provision of abstractions over important |
||||
concepts, Spring provides a facade to metadata implementations, in the |
||||
form of the <interfacename>org.springframework.metadata.Attributes</interfacename> |
||||
interface. Such a facade adds value for several reasons:</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>Even though Java 5 provides metadata support at language level, there will |
||||
still be value in providing such an abstraction: |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>Java 5 metadata is static. It is associated with a class |
||||
at compile time, and cannot be changed in a deployed |
||||
environment (annotation state can actually be changed |
||||
at runtime using reflection, but doing so would really be |
||||
a bad practice). There is a need for hierarchical metadata, |
||||
providing the ability to override certain attribute values in |
||||
deployment - for example, in an XML file.</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para>Java 5 metadata is returned through the Java reflection |
||||
API. This makes it impossible to mock during test time. Spring |
||||
provides a simple interface to allow this.</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para>There will be a need for metadata support in 1.3 and 1.4 |
||||
applications for at least two years. Spring aims to provide |
||||
working solutions <emphasis>now</emphasis>; forcing the use of |
||||
Java 5 is not an option in such an important area.</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</listitem> |
||||
<listitem> |
||||
<para>Current metadata APIs, such as Commons Attributes (used by |
||||
Spring 1.0-1.2) are hard to test. Spring provides a simple metadata |
||||
interface that is much easier to mock.</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
<para>The Spring <interfacename>Attributes</interfacename> interface looks like this:</para> |
||||
<programlisting><![CDATA[public interface Attributes { |
||||
|
||||
Collection getAttributes(Class targetClass); |
||||
|
||||
Collection getAttributes(Class targetClass, Class filter); |
||||
|
||||
Collection getAttributes(Method targetMethod); |
||||
|
||||
Collection getAttributes(Method targetMethod, Class filter); |
||||
|
||||
Collection getAttributes(Field targetField); |
||||
|
||||
Collection getAttributes(Field targetField, Class filter); |
||||
}]]></programlisting> |
||||
<para> |
||||
This is a lowest common denominator interface. JSR-175 offers more |
||||
capabilities than this, such as attributes on method arguments. |
||||
</para> |
||||
<para> |
||||
Note that this interface offers <classname>Object</classname> |
||||
attributes, like .NET. This distinguishes it from attribute systems such |
||||
as that of Nanning Aspects, which offer only <classname>String</classname> |
||||
attributes. There is a significant advantage in supporting |
||||
<classname>Object</classname> attributes, namely that it enables |
||||
attributes to participate in class hierarchies and allows such |
||||
attributes to react intelligently to their configuration parameters. |
||||
</para> |
||||
<para> |
||||
With most attribute providers, attribute classes are configured |
||||
via constructor arguments or JavaBean properties. Commons Attributes |
||||
supports both. |
||||
</para> |
||||
<para>As with all Spring abstraction APIs, <interfacename>Attributes</interfacename> |
||||
is an interface. This makes it easy to mock attribute implementations for unit tests.</para> |
||||
</section> |
||||
<section id="metadata-annotations"> |
||||
<title>Annotations</title> |
||||
<para> |
||||
The Spring Framework ships with a number of custom Java 5+ annotations. |
||||
</para> |
||||
<section id="metadata-annotations-required"> |
||||
<title><interfacename>@Required</interfacename></title> |
||||
<para>The <interfacename>@Required</interfacename> annotation in the |
||||
<literal>org.springframework.beans.factory.annotation</literal> |
||||
package can be used to <emphasis>mark</emphasis> a property as |
||||
being <emphasis>'required-to-be-set'</emphasis> (i.e. an |
||||
annotated (setter) method of a class must be configured to be |
||||
dependency injected with a value), else an |
||||
<classname>Exception</classname> will be thrown by the container |
||||
at runtime.</para> |
||||
<para>The best way to illustrate the usage of this annotation is to |
||||
show an example:</para> |
||||
<programlisting><![CDATA[public class SimpleMovieLister { |
||||
|
||||
]]><lineannotation>// the <classname>SimpleMovieLister</classname> has a dependency on the <interfacename>MovieFinder</interfacename></lineannotation><![CDATA[ |
||||
private MovieFinder movieFinder; |
||||
|
||||
]]><lineannotation>// a setter method so that the Spring container can 'inject' a <interfacename>MovieFinder</interfacename></lineannotation><![CDATA[ |
||||
@Required |
||||
public void setMovieFinder(MovieFinder movieFinder) { |
||||
this.movieFinder = movieFinder; |
||||
} |
||||
|
||||
]]><lineannotation>// business logic that actually 'uses' the injected <interfacename>MovieFinder</interfacename> is omitted...</lineannotation><![CDATA[ |
||||
}]]></programlisting> |
||||
<para> |
||||
Hopefully the above class definition reads easy on the eye. |
||||
Any and all <interfacename>BeanDefinitions</interfacename> for the |
||||
<classname>SimpleMovieLister</classname> class must be provided |
||||
with a value. |
||||
</para> |
||||
<para> |
||||
Let's look at an example of some XML configuration that will |
||||
<emphasis role="bold">not</emphasis> pass validation. |
||||
</para> |
||||
<programlisting><![CDATA[<bean id="movieLister" class="x.y.SimpleMovieLister"> |
||||
]]><lineannotation><!-- whoops, no MovieFinder is set (and this property is <interfacename>@Required</interfacename>) --></lineannotation><![CDATA[ |
||||
</bean>]]></programlisting> |
||||
<para> |
||||
At runtime the following message will be generated by the Spring container |
||||
(the rest of the stack trace has been truncated). |
||||
</para> |
||||
<programlisting><![CDATA[Exception in thread "main" java.lang.IllegalArgumentException: |
||||
Property 'movieFinder' is required for bean 'movieLister'.]]></programlisting> |
||||
<para> |
||||
There is one last little (small, tiny) piece of Spring configuration |
||||
that is required to actually <emphasis>'switch on'</emphasis> this |
||||
behavior. Simply annotating the <emphasis>'setter'</emphasis> properties |
||||
of your classes is not enough to get this behavior. You need |
||||
to enable a component that is aware of the <interfacename>@Required</interfacename> |
||||
annotation and that can process it appropriately. |
||||
</para> |
||||
<para> |
||||
This component is the <classname>RequiredAnnotationBeanPostProcessor</classname> class. |
||||
This is a special <interfacename>BeanPostProcessor</interfacename> |
||||
implementation that is <interfacename>@Required</interfacename>-aware |
||||
and actually provides the <emphasis>'blow up if this required property |
||||
has not been set'</emphasis> logic. It is <emphasis>very</emphasis> easy |
||||
to configure; simply drop the following bean definition into your Spring |
||||
XML configuration. |
||||
</para> |
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>]]></programlisting> |
||||
<para> |
||||
Finally, one can configure an instance of the |
||||
<classname>RequiredAnnotationBeanPostProcessor</classname> class to look |
||||
for <emphasis>another</emphasis> <interfacename>Annotation</interfacename> type. |
||||
This is great if you already have your own |
||||
<interfacename>@Required</interfacename>-style annotation. Simply plug it into |
||||
the definition of a <classname>RequiredAnnotationBeanPostProcessor</classname> and |
||||
you are good to go. |
||||
</para> |
||||
<para> |
||||
By way of an example, let's suppose you (or your organization / team) have |
||||
defined an attribute called @ <interfacename>Mandatory</interfacename>. |
||||
You can make a <classname>RequiredAnnotationBeanPostProcessor</classname> |
||||
instance <interfacename>@Mandatory</interfacename>-aware like so: |
||||
</para> |
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"> |
||||
<property name="requiredAnnotationType" value="your.company.package.Mandatory"/> |
||||
</bean>]]></programlisting> |
||||
<para> |
||||
Here is the source code for the <interfacename>@Mandatory</interfacename> |
||||
annotation. You will need to ensure that your custom annotation type |
||||
is itself annotated with appropriate annotations for its target |
||||
and runtime retention policy. |
||||
</para> |
||||
<programlisting><![CDATA[package your.company.package; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Target(ElementType.METHOD) |
||||
public @interface Mandatory { |
||||
}]]></programlisting> |
||||
</section> |
||||
<section id="metadata-annotations-other"> |
||||
<title>Other @Annotations in Spring</title> |
||||
<para> |
||||
Annotations are also used in a number of other places throughout Spring. |
||||
Rather than being described here, these annotations are described in that |
||||
section or chapter of the reference documentation to which they are most |
||||
relevant. |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para><xref linkend="transaction-declarative-annotations"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="aop-atconfigurable"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="aop-ataspectj"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="beans-annotation-config"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="beans-classpath-scanning"/></para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</section> |
||||
</section> |
||||
<section id="metadata-commons"> |
||||
<title>Integration with Jakarta Commons Attributes</title> |
||||
<para> |
||||
Presently Spring supports only Jakarta Commons Attributes out of the |
||||
box, although it is easy to provide implementations of the |
||||
<interfacename>org.springframework.metadata.Attributes</interfacename> interface for |
||||
other metadata providers. |
||||
</para> |
||||
<para> |
||||
<emphasis role="bold">Commons Attributes 2.2</emphasis> |
||||
(<ulink url="http://jakarta.apache.org/commons/attributes/">http://jakarta.apache.org/commons/attributes/</ulink>) |
||||
is a capable attributes solution. It supports attribute configuration via |
||||
constructor arguments and JavaBean properties, which offers better |
||||
self-documentation in attribute definitions. (Support for JavaBean |
||||
properties was added at the request of the Spring team.) |
||||
</para> |
||||
<para> |
||||
We've already seen two examples of Commons Attributes attributes |
||||
definitions. In general, we will need to express: |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para> |
||||
<emphasis>The name of the attribute class</emphasis>. This can |
||||
be a fully qualified name (FQN), as shown above. If the relevant attribute class has already |
||||
been imported, the FQN isn't required. It's also possible to specify |
||||
"attribute packages" in attribute compiler configuration. |
||||
</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para> |
||||
<emphasis>Any necessary parameterization.</emphasis> This is done via |
||||
constructor arguments or JavaBean properties. |
||||
</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
<para>Bean properties look as follows:</para> |
||||
<programlisting><![CDATA[/** |
||||
* @@MyAttribute(myBooleanJavaBeanProperty=true) |
||||
*/]]></programlisting> |
||||
<para> |
||||
It's possible to combine constructor arguments and JavaBean |
||||
properties (as in Spring IoC). |
||||
</para> |
||||
<para> |
||||
Because, unlike Java 1.5 attributes, Commons Attributes is not |
||||
integrated with the Java language, it is necessary to run a special |
||||
<emphasis>attribute compilation</emphasis> step as part of the build |
||||
process. |
||||
</para> |
||||
<para> |
||||
To run Commons Attributes as part of the build process, you will |
||||
need to do the following: |
||||
</para> |
||||
<para> |
||||
1. Copy the necessary library jars to |
||||
<literal>$ANT_HOME/lib</literal>. Four Jars are required, and all are |
||||
distributed with Spring: |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>the Commons Attributes compiler jar and API jar</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para>xJavadoc.jar from XDoclet</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para>commons-collections.jar from Jakarta Commons</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
<para> |
||||
2. Import the Commons Attributes ant tasks into your project build |
||||
script, as follows: |
||||
</para> |
||||
<programlisting><![CDATA[<taskdef resource="org/apache/commons/attributes/anttasks.properties"/>]]></programlisting> |
||||
<para> |
||||
3. Next, define an attribute compilation task, which will use the |
||||
Commons Attributes attribute-compiler task to "compile" the attributes in |
||||
the source. This process results in the generation of additional sources, |
||||
to a location specified by the <literal>destdir</literal> attribute. Here we show the use of |
||||
a temporary directory for storing the generated files: |
||||
</para> |
||||
<programlisting><![CDATA[<target name="compileAttributes"> |
||||
|
||||
<attribute-compiler destdir="${commons.attributes.tempdir}"> |
||||
<fileset dir="${src.dir}" includes="**/*.java"/> |
||||
</attribute-compiler> |
||||
|
||||
</target>]]></programlisting> |
||||
<para> |
||||
The compile target that runs javac over the sources should depend on |
||||
this attribute compilation task, and must also compile the generated |
||||
sources, which we output to our destination temporary directory. If there |
||||
are syntax errors in your attribute definitions, they will normally be |
||||
caught by the attribute compiler. However, if the attribute definitions |
||||
are syntactically plausible, but specify invalid types or class names, the |
||||
compilation of the generated attribute classes may fail. In this case, you |
||||
can look at the generated classes to establish the cause of the |
||||
problem. |
||||
</para> |
||||
<remark> |
||||
Commons Attributes also provides Maven support. Please refer to |
||||
Commons Attributes documentation for further information. |
||||
</remark> |
||||
<para> |
||||
While this attribute compilation process may look complex, in fact |
||||
it's a one-off cost. Once set up, attribute compilation is incremental, so |
||||
it doesn't usually noticeably slow the build process. And once the |
||||
compilation process is set up, you may find that use of attributes as |
||||
described in this chapter can save you a lot of time in other |
||||
areas. |
||||
</para> |
||||
<para> |
||||
If you require attribute indexing support (only currently required |
||||
by Spring for attribute-targeted web controllers, discussed below), you |
||||
will need an additional step, which must be performed on a jar file of |
||||
your compiled classes. In this additional step, Commons Attributes will |
||||
create an index of all the attributes defined on your sources, for |
||||
efficient lookup at runtime. The step looks like this: |
||||
</para> |
||||
<programlisting><![CDATA[<attribute-indexer jarFile="myCompiledSources.jar"> |
||||
|
||||
<classpath refid="master-classpath"/> |
||||
|
||||
</attribute-indexer>]]></programlisting> |
||||
<remark> |
||||
See the <literal>/attributes</literal> directory of the Spring JPetStore sample |
||||
application for an example of this build process. You can take the build |
||||
script it contains and modify it for your own projects. |
||||
</remark> |
||||
<para> |
||||
If your unit tests depend on attributes, try to express the |
||||
dependency on the Spring Attributes abstraction, rather than Commons |
||||
Attributes. Not only is this more portable - for example, your tests will |
||||
still work if you switch to Java 1.5 attributes in future - it simplifies |
||||
testing. Also, Commons Attributes is a static API, while Spring provides a |
||||
metadata interface that you can easily mock. |
||||
</para> |
||||
</section> |
||||
<section id="metadata-uses"> |
||||
<title>Metadata and Spring AOP autoproxying</title> |
||||
<para> |
||||
The most important uses of metadata attributes are in conjunction |
||||
with Spring AOP. This provides a .NET-like programming model, where |
||||
declarative services are automatically provided to application objects |
||||
that declare metadata attributes. Such metadata attributes can be |
||||
supported out of the box by the framework, as in the case of declarative |
||||
transaction management, or can be custom. |
||||
</para> |
||||
<section id="metadata-fundamentals"> |
||||
<title>Fundamentals</title> |
||||
<para> |
||||
This builds on the Spring AOP autoproxy functionality. |
||||
Configuration might look like this: |
||||
</para> |
||||
<programlisting><![CDATA[<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> |
||||
|
||||
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> |
||||
<property name="transactionInterceptor" ref="txInterceptor" /> |
||||
</bean> |
||||
|
||||
<bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> |
||||
<property name="transactionManager" ref="transactionManager" /> |
||||
<property name="transactionAttributeSource"> |
||||
<bean class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource"> |
||||
<property name="attributes" ref="attributes" /> |
||||
</bean> |
||||
</property> |
||||
</bean> |
||||
|
||||
<bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes" />]]></programlisting> |
||||
<para> |
||||
The basic concepts here should be familiar from the discussion of |
||||
autoproxying in the AOP chapter. |
||||
</para> |
||||
<para> |
||||
The most important bean definitions are the auto-proxy creator |
||||
and the advisor. Note that the actual bean names are not important; |
||||
what matters is their class. |
||||
</para> |
||||
<para> |
||||
The bean definition of class |
||||
<classname>org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator</classname> |
||||
will automatically advise ("auto-proxy") all bean instances in the |
||||
current factory based on matching advisor implementations. This class |
||||
knows nothing about attributes, but relies on advisors' pointcuts |
||||
matching. The pointcuts, however, do know about attributes. |
||||
</para> |
||||
<para> |
||||
Thus we simply need an AOP advisor that will provide declarative |
||||
transaction management based on attributes. |
||||
</para> |
||||
<para> |
||||
It is possible to add arbitrary custom advisor implementations as |
||||
well, and they will also be evaluated and applied automatically. (You |
||||
can use advisors whose pointcuts match on criteria besides attributes in |
||||
the same autoproxy configuration, if necessary.) |
||||
</para> |
||||
<para> |
||||
Finally, the <literal>attributes</literal> bean is the Commons |
||||
Attributes Attributes implementation. Replace it with another |
||||
implementation of the |
||||
<interfacename>org.springframework.metadata.Attributes</interfacename> |
||||
interface to source attributes from a different source. |
||||
</para> |
||||
</section> |
||||
<section id="metadata-tx"> |
||||
<title>Declarative transaction management</title> |
||||
<para> |
||||
The most common use of source-level attributes is to provide |
||||
declarative transaction management. Once the bean definitions |
||||
shown above are in place, you can define any number of application |
||||
objects requiring declarative transactions. Only those classes or |
||||
methods with transaction attributes will be given transaction advice. |
||||
You need to do nothing except define the required transaction |
||||
attributes. |
||||
</para> |
||||
<para>Please note that you can specify transaction attributes at either class |
||||
or method level. Class-level attributes, if specified, will be "inherited" |
||||
by all methods whereas method attributes will wholly override any |
||||
class-level attributes.</para> |
||||
</section> |
||||
</section> |
||||
</chapter> |
||||
@ -0,0 +1,796 @@
@@ -0,0 +1,796 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<chapter id="new-in-2"> |
||||
<title>What's new in Spring 2.0 and 2.5?</title> |
||||
|
||||
<section id="new-in-2-intro"> |
||||
<title>Introduction</title> |
||||
|
||||
<para>If you have been using the Spring Framework for some time, you will |
||||
be aware that Spring has undergone two major revisions: Spring 2.0, |
||||
released in October 2006, and Spring 2.5, released in November 2007.</para> |
||||
|
||||
<sidebar id="new-in-2-intro-java"> |
||||
<title>Java SE and Java EE Support</title> |
||||
|
||||
<para>The Spring Framework continues to be compatible with all versions |
||||
of Java since (and including) Java 1.4.2. This means that Java 1.4.2, |
||||
Java 5 and Java 6 are supported, although some advanced functionality of |
||||
the Spring Framework will not be available to you if you are committed to |
||||
using Java 1.4.2. Spring 2.5 introduces dedicated support for Java 6, |
||||
after Spring 2.0's in-depth support for Java 5 throughout the |
||||
framework.</para> |
||||
|
||||
<para>Furthermore, Spring remains compatible with J2EE 1.3 and higher, |
||||
while at the same time introducing dedicated support for Java EE 5. This |
||||
means that Spring can be consistently used on application servers such |
||||
as BEA WebLogic 8.1, 9.0, 9.2 and 10, IBM WebSphere 5.1, 6.0, 6.1 and 7, |
||||
Oracle OC4J 10.1.3 and 11, JBoss 3.2, 4.0, 4.2 and 5.0, as well as Tomcat |
||||
4.1, 5.0, 5.5 and 6.0, Jetty 4.2, 5.1 and 6.1, Resin 2.1, 3.0 and 3.1 |
||||
and GlassFish V1 and V2.</para> |
||||
|
||||
<para><emphasis>NOTE: We generally recommend using the most recent |
||||
version of each application server generation. In particular, |
||||
make sure you are using BEA WebLogic 8.1 SP6 or higher and |
||||
WebSphere 6.0.2.19 / 6.1.0.9 or higher, respectively, when using |
||||
those WebLogic and WebSphere generations with Spring 2.5.</emphasis></para> |
||||
</sidebar> |
||||
|
||||
<para>This chapter is a guide to the new and improved features of Spring |
||||
2.0 and 2.5. It is intended to provide a high-level summary so that |
||||
seasoned Spring architects and developers can become immediately familiar |
||||
with the new Spring 2.x functionality. For more in-depth information on |
||||
the features, please refer to the corresponding sections hyperlinked from |
||||
within this chapter.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-ioc"> |
||||
<title>The Inversion of Control (IoC) container</title> |
||||
|
||||
<para>One of the areas that contains a considerable number of 2.0 |
||||
and 2.5 improvements is Spring's IoC container.</para> |
||||
|
||||
<section id="new-in-2-ioc-scopes"> |
||||
<title>New bean scopes</title> |
||||
|
||||
<para>Previous versions of Spring had IoC container level support for |
||||
exactly two distinct bean scopes (singleton and prototype). Spring 2.0 |
||||
improves on this by not only providing a number of additional scopes |
||||
depending on the environment in which Spring is being deployed (for |
||||
example, request and session scoped beans in a web environment), but |
||||
also by providing integration points so that Spring users can create |
||||
their own scopes.</para> |
||||
|
||||
<para>It should be noted that although the underlying (and internal) |
||||
implementation for singleton- and prototype-scoped beans has been |
||||
changed, this change is totally transparent to the end user... no |
||||
existing configuration needs to change, and no existing configuration |
||||
will break.</para> |
||||
|
||||
<para>Both the new and the original scopes are detailed in the section |
||||
entitled <xref linkend="beans-factory-scopes"/>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-ioc-configuration"> |
||||
<title>Easier XML configuration</title> |
||||
|
||||
<para>Spring XML configuration is now even easier, thanks to the advent |
||||
of the new XML configuration syntax based on XML Schema. If you want to |
||||
take advantage of the new tags that Spring provides (and the Spring team |
||||
certainly suggest that you do because they make configuration less |
||||
verbose and easier to read), then do read the section entitled <xref |
||||
linkend="xsd-config"/>.</para> |
||||
|
||||
<para>On a related note, there is a new, updated DTD for Spring 2.0 that |
||||
you may wish to reference if you cannot take advantage of the XML |
||||
Schema-based configuration. The DOCTYPE declaration is included below |
||||
for your convenience, but the interested reader should definitely read |
||||
the <filename>'spring-beans-2.0.dtd'</filename> DTD included in the |
||||
<filename class="directory">'dist/resources'</filename> directory of the |
||||
Spring 2.5 distribution.</para> |
||||
|
||||
<programlisting><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" |
||||
"http://www.springframework.org/dtd/spring-beans-2.0.dtd"></programlisting> |
||||
</section> |
||||
|
||||
<section id="new-in-2-ioc-custom-configuration"> |
||||
<title>Extensible XML authoring</title> |
||||
|
||||
<para>Not only is XML configuration easier to write, it is now also |
||||
extensible.</para> |
||||
|
||||
<para>What 'extensible' means in this context is that you, as an |
||||
application developer, or (more likely) as a third party framework or |
||||
product vendor, can write custom tags that other developers can then |
||||
plug into their own Spring configuration files. This allows you to have |
||||
your own domain specific language (the term is used loosely here) of |
||||
sorts be reflected in the specific configuration of your own |
||||
components.</para> |
||||
|
||||
<para>Implementing custom Spring tags may not be of interest to every |
||||
single application developer or enterprise architect using Spring in |
||||
their own projects. We expect third-party vendors to be highly |
||||
interested in developing custom configuration tags for use in Spring |
||||
configuration files.</para> |
||||
|
||||
<para>The extensible configuration mechanism is documented in <xref |
||||
linkend="extensible-xml"/>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-ioc-annotations"> |
||||
<title>Annotation-driven configuration</title> |
||||
|
||||
<para>Spring 2.0 introduced support for various annotations for |
||||
configuration purposes, such as <interfacename>@Transactional</interfacename>, |
||||
<interfacename>@Required</interfacename> and <interfacename>@PersistenceContext</interfacename> |
||||
/<interfacename>@PersistenceUnit</interfacename>.</para> |
||||
|
||||
<para>Spring 2.5 introduces support for a complete set of configuration |
||||
annotations: <interfacename>@Autowired</interfacename> in combination |
||||
with support for the JSR-250 annotations <interfacename>@Resource</interfacename>, |
||||
<interfacename>@PostConstruct</interfacename> and <interfacename>@PreDestroy</interfacename> |
||||
.</para> |
||||
|
||||
<para>Annotation-driven bean configuration is discussed in <xref |
||||
linkend="beans-annotation-config"/>. Check out annotation support |
||||
for Spring MVC as well: <xref linkend="new-in-2-web-annotations"/></para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-ioc-component-scanning"> |
||||
<title>Autodetecting components in the classpath</title> |
||||
|
||||
<para>Spring 2.5 introduces support component scanning: autodetecting |
||||
annotated components in the classpath. Typically, such component classes |
||||
will be annotated with stereotypes such as <interfacename>@Component</interfacename>, |
||||
<interfacename>@Repository</interfacename>, <interfacename>@Service</interfacename>, |
||||
<interfacename>@Controller</interfacename>. Depending on the application |
||||
context configuration, such component classes will be autodetected and |
||||
turned into Spring bean definitions, not requiring explicit configuration |
||||
for each such bean.</para> |
||||
|
||||
<para>Annotation-driven bean configuration is discussed in <xref |
||||
linkend="beans-stereotype-annotations"/>.</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="new-in-2-aop"> |
||||
<title>Aspect Oriented Programming (AOP)</title> |
||||
|
||||
<para>Spring 2.0 has a much improved AOP offering. The Spring AOP |
||||
framework itself is markedly easier to configure in XML, and significantly |
||||
less verbose as a result; and Spring 2.0 integrates with the AspectJ |
||||
pointcut language and @AspectJ aspect declaration style. The chapter |
||||
entitled <xref linkend="aop"/> is dedicated to describing this new |
||||
support.</para> |
||||
|
||||
<section id="new-in-2-aop-configuration"> |
||||
<title>Easier AOP XML configuration</title> |
||||
|
||||
<para>Spring 2.0 introduces new schema support for defining aspects |
||||
backed by regular Java objects. This support takes advantage of the |
||||
AspectJ pointcut language and offers fully typed advice (i.e. no more |
||||
casting and <literal>Object[]</literal> argument manipulation). Details |
||||
of this support can be found in the section entitled <xref |
||||
linkend="aop-schema"/>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-aop-aspectj"> |
||||
<title>Support for @AspectJ aspects</title> |
||||
|
||||
<para>Spring 2.0 also supports aspects defined using the @AspectJ |
||||
annotations. These aspects can be shared between AspectJ and Spring AOP, |
||||
and require (honestly!) only some simple configuration. Said support for |
||||
@AspectJ aspects is discussed in <xref |
||||
linkend="aop-ataspectj"/>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-aop-bean-pointcuts"> |
||||
<title>Support for bean name pointcut element</title> |
||||
|
||||
<para>Spring 2.5 introduces support for the <literal>bean(...)</literal> |
||||
pointcut element, matching specific named beans according to Spring-defined |
||||
bean names. See <xref linkend="aop-pointcuts-designators"/> for details.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-aop-load-time-weaving"> |
||||
<title>Support for AspectJ load-time weaving</title> |
||||
|
||||
<para>Spring 2.5 introduces explicit support AspectJ load-time weaving, |
||||
as alternative to the proxy-based AOP framework. The new |
||||
<literal>context:load-time-weaver</literal> configuration element |
||||
automatically activates AspectJ aspects as defined in AspectJ's |
||||
<literal>META-INF/aop.xml</literal> descriptor, applying them to the |
||||
current application context through registering a transformer with the |
||||
underlying ClassLoader. Note that this only works in environments with |
||||
class transformation support. Check out <xref linkend="aop-aj-ltw"/> |
||||
for the capabilities and limitations.</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="new-in-2-middle-tier"> |
||||
<title>The Middle Tier</title> |
||||
|
||||
<section id="new-in-2-middle-tier-transaction-configuration"> |
||||
<title>Easier configuration of declarative transactions in XML</title> |
||||
|
||||
<para>The way that transactions are configured in Spring 2.0 has been |
||||
changed significantly. The previous 1.2.x style of configuration |
||||
continues to be valid (and supported), but the new style is markedly |
||||
less verbose and is the recommended style. Spring 2.0 also ships with an |
||||
AspectJ aspects library that you can use to make pretty much any object |
||||
transactional - even objects not created by the Spring IoC container.</para> |
||||
|
||||
<para>Spring 2.5 supports convenient annotation-driven transaction |
||||
management in combination with load-time weaving, through the use of |
||||
<literal>context:load-time-weaver</literal> in combination with |
||||
<literal>tx:annotation-driven mode="aspectj"</literal>.</para> |
||||
|
||||
<para>The chapter entitled <xref linkend="transaction"/> contains all |
||||
of the details.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-middle-tier-websphere"> |
||||
<title>Full WebSphere transaction management support</title> |
||||
|
||||
<para>Spring 2.5 explicitly supports IBM's WebSphere Application Server, |
||||
in particular with respect to WebSphere's transaction manager. |
||||
Transaction suspension is now fully supported through the use of |
||||
WebSphere's new <interfacename>UOWManager</interfacename> API, which |
||||
is available on WAS 6.0.2.19+ and 6.0.1.9+.</para> |
||||
|
||||
<para>So if you run a Spring-based application on the WebSphere |
||||
Application Server, we highly recommend to use Spring 2.5's |
||||
<classname>WebSphereUowTransactionManager</classname> as your |
||||
<interfacename>PlatformTransactionManager</interfacename> of choice. |
||||
This is also IBM's official recommendation.</para> |
||||
|
||||
<para>For automatic detection of the underlying JTA-based transaction |
||||
platform, consider the use of Spring 2.5's new |
||||
<literal>tx:jta-transaction-manager</literal> configuration element. |
||||
This will autodetect BEA WebLogic and IBM WebSphere, registering the |
||||
appropriate <interfacename>PlatformTransactionManager</interfacename>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-middle-tier-jpa"> |
||||
<title>JPA</title> |
||||
|
||||
<para>Spring 2.0 ships with a JPA abstraction layer that is similar in |
||||
intent to Spring's JDBC abstraction layer in terms of scope and general |
||||
usage patterns.</para> |
||||
|
||||
<para>If you are interested in using a JPA-implementation as the |
||||
backbone of your persistence layer, the section entitled <xref |
||||
linkend="orm-jpa"/> is dedicated to detailing Spring's support and |
||||
value-add in this area.</para> |
||||
|
||||
<para>Spring 2.5 upgrades its OpenJPA support to OpenJPA 1.0, |
||||
with support for advanced features such as savepoints.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-middle-tier-async-jms"> |
||||
<title>Asynchronous JMS</title> |
||||
|
||||
<para>Prior to Spring 2.0, Spring's JMS offering was limited to sending |
||||
messages and the <emphasis>synchronous</emphasis> receiving of messages. |
||||
This functionality (encapsulated in the |
||||
<classname>JmsTemplate</classname> class) is great, but it doesn't |
||||
address the requirement for the <emphasis>asynchronous</emphasis> |
||||
receiving of messages.</para> |
||||
|
||||
<para>Spring 2.0 now ships with full support for the reception of |
||||
messages in an asynchronous fashion, as detailed in the section entitled |
||||
<xref linkend="jms-asynchronousMessageReception"/>.</para> |
||||
|
||||
<para>As of Spring 2.5, the JCA style of setting up asynchronous |
||||
message listeners is supported as well, through the |
||||
<classname>GenericMessageEndpointManager</classname> facility. |
||||
This is an alternative to the standard JMS listener facility, allowing |
||||
closer integration with message brokers such as ActiveMQ and JORAM. |
||||
See <xref linkend="jms-jca-message-endpoint-manager"/>.</para> |
||||
|
||||
<para>Spring 2.5 also introduces an XML namespace for simplifying JMS |
||||
configuration, offering concise configuration of a large numbers of |
||||
listeners. This namespace supports both the standard JMS listener facility |
||||
as well as the JCA setup style, with minimal changes in the configuration. |
||||
See <xref linkend="jms-namespace"/>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-middle-tier-jdbc"> |
||||
<title>JDBC</title> |
||||
|
||||
<para>There are some small (but nevertheless notable) new classes in the |
||||
Spring Framework's JDBC support library. The first, <link |
||||
linkend="jdbc-NamedParameterJdbcTemplate"><classname>NamedParameterJdbcTemplate</classname></link>, |
||||
provides support for programming JDBC statements using named parameters |
||||
(as opposed to programming JDBC statements using only classic |
||||
placeholder (<literal>'?'</literal>) arguments.</para> |
||||
|
||||
<para>Another of the new classes, the <link |
||||
linkend="jdbc-SimpleJdbcTemplate"><classname>SimpleJdbcTemplate</classname></link>, |
||||
is aimed at making using the <classname>JdbcTemplate</classname> even |
||||
easier to use when you are developing against Java 5+ (Tiger).</para> |
||||
|
||||
<para>Spring 2.5 significantly extends the functionality of |
||||
<classname>SimpleJdbcTemplate</classname> and introduces |
||||
<classname>SimpleJdbcCall</classname> and <classname>SimpleJdbcInsert</classname> |
||||
operation objects. |
||||
</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="new-in-2-web"> |
||||
<title>The Web Tier</title> |
||||
|
||||
<para>The web tier support has been <emphasis>substantially</emphasis> |
||||
improved and expanded in Spring 2.0, with annotation-based controllers |
||||
introduced in Spring 2.5.</para> |
||||
|
||||
<section id="new-in-2-web-convention"> |
||||
<title>Sensible defaulting in Spring MVC</title> |
||||
|
||||
<para>For a lot of projects, sticking to established conventions and |
||||
having reasonable defaults is just what the projects need... this theme |
||||
of convention-over-configuration now has explicit support in Spring MVC. |
||||
What this means is that if you establish a set of naming conventions for |
||||
your <literal>Controllers</literal> and views, you can |
||||
<emphasis>substantially</emphasis> cut down on the amount of XML |
||||
configuration that is required to setup handler mappings, view |
||||
resolvers, <classname>ModelAndView</classname> instances, etc. This is a |
||||
great boon with regards to rapid prototyping, and can also lend a degree |
||||
of (always good-to-have) consistency across a codebase.</para> |
||||
|
||||
<para>Spring MVC's convention-over-configuration support is detailed in |
||||
the section entitled <xref linkend="mvc-coc"/></para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-web-portlet"> |
||||
<title>Portlet framework</title> |
||||
|
||||
<para>Spring 2.0 ships with a Portlet framework that is conceptually |
||||
similar to the Spring MVC framework. Detailed coverage of the Spring |
||||
Portlet framework can be found in the section entitled <xref |
||||
linkend="portlet"/>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-web-annotations"> |
||||
<title>Annotation-based controllers</title> |
||||
|
||||
<para>Spring 2.5 introduces an annotation-based programming model for MVC |
||||
controllers, using annotations such as <interfacename>@RequestMapping</interfacename>, |
||||
<interfacename>@RequestParam</interfacename>, <interfacename>@ModelAttribute</interfacename>, |
||||
etc. This annotation support is available for both Servlet MVC and Portlet |
||||
MVC. Controllers implemented in this style do not have to extend specific |
||||
base classes or implement specific interfaces. Furthermore, they do not |
||||
usually have direct dependencies on Servlet or Portlet API's, although |
||||
they can easily get access to Servlet or Portlet facilities if desired. |
||||
For further details, see <xref linkend="mvc-annotation"/>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-web-form-tags"> |
||||
<title>A form tag library for Spring MVC</title> |
||||
|
||||
<para>A rich JSP tag library for Spring MVC was <emphasis>the</emphasis> |
||||
JIRA issue that garnered the most votes from Spring users (by a wide |
||||
margin).</para> |
||||
|
||||
<para>Spring 2.0 ships with a full featured JSP tag library that makes |
||||
the job of authoring JSP pages much easier when using Spring MVC; the |
||||
Spring team is confident it will satisfy all of those developers who |
||||
voted for the issue on JIRA. The new tag library is itself covered in |
||||
the section entitled <xref linkend="view-jsp-formtaglib"/>, and a quick |
||||
reference to all of the new tags can be found in the appendix entitled |
||||
<xref linkend="spring-form.tld"/>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-web-tiles2"> |
||||
<title>Tiles 2 support</title> |
||||
|
||||
<para>Spring 2.5 ships support for Tiles 2, the next generation of the |
||||
popular Tiles templating framework. This supersedes Spring's former support |
||||
for Tiles 1, as included in Struts 1.x. See <xref linkend="view-tiles"/> |
||||
for details.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-web-jsf12"> |
||||
<title>JSF 1.2 support</title> |
||||
|
||||
<para>Spring 2.5 supports JSF 1.2, providing a JSF 1.2 variant of Spring's |
||||
<classname>DelegatingVariableResolver</classname> in the form of the new |
||||
<classname>SpringBeanFacesELResolver</classname>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-web-jaxws"> |
||||
<title>JAX-WS support</title> |
||||
|
||||
<para>Spring 2.5 fully supports JAX-WS 2.0/2.1, as included in Java 6 and Java EE 5. |
||||
JAX-WS is the successor of JAX-RPC, allowing access to WSDL/SOAP-based web |
||||
services as well as JAX-WS style exposure of web services.</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="new-in-2-other"> |
||||
<title>Everything else</title> |
||||
|
||||
<para>This final section outlines all of the other new and improved Spring |
||||
2.0/2.5 features and functionality.</para> |
||||
|
||||
<section id="new-in-2-other-dynamic-language-support"> |
||||
<title>Dynamic language support</title> |
||||
|
||||
<para>Spring 2.0 introduced support for beans written in languages other |
||||
than Java, with the currently supported dynamic languages being JRuby, |
||||
Groovy and BeanShell. This dynamic language support is comprehensively |
||||
detailed in the section entitled <xref linkend="dynamic-language"/>.</para> |
||||
|
||||
<para>Spring 2.5 refines the dynamic languages support with autowiring |
||||
and support for the recently released JRuby 1.0.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-other-testing"> |
||||
<title>Enhanced testing support</title> |
||||
|
||||
<para>Spring 2.5 introduces the <emphasis>Spring TestContext |
||||
Framework</emphasis> which provides annotation-driven unit and integration |
||||
testing support that is agnostic of the actual testing framework in use. |
||||
The same techniques and annotation-based configuration used in, for |
||||
example, a JUnit 3.8 environment can also be applied to tests written with |
||||
JUnit 4.4, TestNG, etc.</para> |
||||
|
||||
<para>In addition to providing generic and extensible testing |
||||
infrastructure, the <emphasis>Spring TestContext Framework</emphasis> |
||||
provides out-of-the-box support for Spring-specific integration testing |
||||
functionality such as <link linkend="testcontext-ctx-management">context |
||||
management and caching</link>, <link |
||||
linkend="testcontext-fixture-di">dependency injection of test |
||||
fixtures</link>, and <link linkend="testcontext-tx">transactional test |
||||
management</link> with default rollback semantics.</para> |
||||
|
||||
<para>To discover how this new testing support can assist you with writing |
||||
unit and integration tests, consult <xref linkend="testcontext-framework"/> |
||||
of the revised testing chapter.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-other-jmx"> |
||||
<title>JMX support</title> |
||||
|
||||
<para>The Spring Framework 2.0 has support for |
||||
<literal>Notifications</literal>; it is also possible to exercise |
||||
declarative control over the registration behavior of MBeans with an |
||||
<literal>MBeanServer</literal>.</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<xref linkend="jmx-notifications"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="jmx-exporting-registration-behavior"/> |
||||
</listitem> |
||||
</itemizedlist> |
||||
|
||||
<para>Furthermore, Spring 2.5 provides a |
||||
<link linkend="jmx-context-mbeanexport"><literal>context:mbean-export</literal></link> |
||||
configuration element for convenient registration of annotated bean classes, |
||||
detecting Spring's <interfacename>@ManagedResource</interfacename> annotation.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-other-jca"> |
||||
<title>Deploying a Spring application context as JCA adapter</title> |
||||
|
||||
<para>Spring 2.5 supports the deployment of a Spring application context |
||||
as JCA resource adapter, packaged as a JCA RAR file. This allows headless |
||||
application modules to be deployed into J2EE servers, getting access to |
||||
all the server's infrastructure e.g. for executing scheduled tasks, |
||||
listening for incoming messages, etc.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-other-taskexecutor"> |
||||
<title>Task scheduling</title> |
||||
|
||||
<para>Spring 2.0 offers an abstraction around the scheduling of tasks. |
||||
For the interested developer, the section entitled <xref |
||||
linkend="scheduling-task-executor"/> contains all of the |
||||
details.</para> |
||||
|
||||
<para>The <interfacename>TaskExecutor</interfacename> abstraction is used |
||||
throughout the framework itself as well, e.g. for the asynchronous JMS support. |
||||
In Spring 2.5, it is also used in the JCA environment support.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-other-java5"> |
||||
<title>Java 5 (Tiger) support</title> |
||||
|
||||
<para>Find below pointers to documentation describing some of the new |
||||
Java 5 support in Spring 2.0 and 2.5.</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<xref linkend="beans-annotation-config"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="metadata-annotations-required"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="transaction-declarative-annotations"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="jdbc-SimpleJdbcTemplate"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="orm-jpa"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="aop-ataspectj"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="aop-atconfigurable"/> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="new-in-2-migrating"> |
||||
<title>Migrating to Spring 2.5</title> |
||||
|
||||
<para>This final section details issues that may arise during any |
||||
migration from Spring 1.2/2.0 to Spring 2.5.</para> |
||||
|
||||
<para>Upgrading to Spring 2.5 from a Spring 2.0.x application should |
||||
simply be a matter of dropping the Spring 2.5 jar into the appropriate |
||||
location in your application's directory structure. We highly recommend |
||||
upgrading to Spring 2.5 from any Spring 2.0 application that runs on |
||||
JDK 1.4.2 or higher, in particular when running on Java 5 or higher, |
||||
leveraging the significant configuration conveniences and performance |
||||
improvements that Spring 2.5 has to offer.</para> |
||||
|
||||
<para>Whether an upgrade from Spring 1.2.x will be as seamless depends on |
||||
how much of the Spring APIs you are using in your code. Spring 2.0 |
||||
removed pretty much all of the classes and methods previously marked |
||||
as deprecated in the Spring 1.2.x codebase, so if you have been using |
||||
such classes and methods, you will of course have to use alternative |
||||
classes and methods (some of which are summarized below).</para> |
||||
|
||||
<para>With regards to configuration, Spring 1.2.x style XML configuration |
||||
is 100%, satisfaction-guaranteed compatible with the Spring 2.5 library. |
||||
Of course if you are still using the Spring 1.2.x DTD, then you won't be |
||||
able to take advantage of some of the new Spring 2.0 functionality (such |
||||
as <link linkend="new-in-2-ioc-scopes">scopes</link> and <link |
||||
linkend="new-in-2-aop-configuration">easier AOP</link> and <link |
||||
linkend="new-in-2-middle-tier-transaction-configuration">transaction |
||||
configuration</link>), but nothing will blow up.</para> |
||||
|
||||
<para>The suggested migration strategy is to drop in the Spring 2.5 jar(s) |
||||
to benefit from the improved code present in the release (bug fixes, |
||||
optimizations, etc.). You can then, on an incremental basis, choose to |
||||
start using the new Spring 2.5 features and configuration. For example, |
||||
you could choose to start configuring just your aspects in the new Spring |
||||
2 style; it is perfectly valid to have 90% of your configuration using |
||||
the old-school Spring 1.2.x configuration (which references the 1.2.x |
||||
DTD), and have the other 10% using the new Spring 2 configuration (which |
||||
references the 2.0/2.5 DTD or XSD). Bear in mind that you are not forced to |
||||
upgrade your XML configuration should you choose to drop in the Spring 2.5 |
||||
libraries.</para> |
||||
|
||||
<section id="new-in-2-migrating-changes"> |
||||
<title>Changes</title> |
||||
|
||||
<para>For a comprehensive list of changes, consult the |
||||
<filename>'changelog.txt'</filename> file that is located in the top |
||||
level directory of the Spring Framework distribution.</para> |
||||
|
||||
<section id="new-in-2-migrating-jdk"> |
||||
<title>Supported JDK versions</title> |
||||
|
||||
<para>As of Spring 2.5, support for JDK 1.3 has been removed, |
||||
following Sun's official deprecation of JDK 1.3 in late 2006. |
||||
If you haven't done so already, upgrade to JDK 1.4.2 or higher.</para> |
||||
|
||||
<para>If you need to stick with an application server that only supports |
||||
JDK 1.3, such as WebSphere 4.0 or 5.0, we recommend using the |
||||
Spring Framework version 2.0.7/2.0.8 which still supports JDK 1.3.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-migrating-packaging"> |
||||
<title>Jar packaging in Spring 2.5</title> |
||||
|
||||
<para>As of Spring 2.5, Spring Web MVC is no longer part of the |
||||
<filename class="libraryfile">'spring.jar'</filename> file. Spring MVC |
||||
can be found in <filename class="libraryfile">'spring-webmvc.jar'</filename> |
||||
and <filename class="libraryfile">'spring-webmvc-portlet.jar'</filename> |
||||
in the <literal>lib/modules</literal> directory of the distribution. |
||||
Furthermore, the Struts 1.x support has been factored out into |
||||
<filename class="libraryfile">'spring-webmvc-struts.jar'</filename>.</para> |
||||
|
||||
<para><emphasis>Note: The commonly used Spring's <classname>DispatcherServlet</classname> |
||||
is part of Spring's Web MVC framework.</emphasis> As a consequence, |
||||
you need to add <filename class="libraryfile">'spring-webmvc.jar'</filename> |
||||
(or <filename class="libraryfile">'spring-webmvc-portlet/struts.jar'</filename>) |
||||
to a <filename class="libraryfile">'spring.jar'</filename> scenario, |
||||
even if you are just using <classname>DispatcherServlet</classname> |
||||
for remoting purposes (e.g. exporting Hessian or HTTP invoker services).</para> |
||||
|
||||
<para>Spring 2.0's <filename class="libraryfile">'spring-jmx.jar'</filename> |
||||
and <filename class="libraryfile">'spring-remoting.jar'</filename> have been |
||||
merged into Spring 2.5's <filename class="libraryfile">'spring-context.jar'</filename> |
||||
(for the JMX and non-HTTP remoting support) and partly into |
||||
<filename class="libraryfile">'spring-web.jar'</filename> |
||||
(for the HTTP remoting support).</para> |
||||
|
||||
<para>Spring 2.0's <filename class="libraryfile">'spring-support.jar'</filename> |
||||
has been renamed to <filename class="libraryfile">'spring-context-support.jar'</filename>, |
||||
expressing the actual support relationship more closely. |
||||
<filename class="libraryfile">'spring-portlet.jar'</filename> has been |
||||
renamed to <filename class="libraryfile">'spring-webmvc-portlet.jar'</filename>, |
||||
since it is technically a submodule of Spring's Web MVC framework. |
||||
Analogously, <filename class="libraryfile">'spring-struts.jar'</filename> |
||||
has been renamed to <filename class="libraryfile">'spring-webmvc-struts.jar'</filename>. |
||||
</para> |
||||
|
||||
<para>Spring 2.0's <filename class="libraryfile">'spring-jdo.jar'</filename>, |
||||
<filename class="libraryfile">'spring-jpa.jar'</filename>, |
||||
<filename class="libraryfile">'spring-hibernate3.jar'</filename>, |
||||
<filename class="libraryfile">'spring-toplink.jar'</filename> |
||||
and <filename class="libraryfile">'spring-ibatis.jar'</filename> |
||||
have been combined into Spring 2.5's coarse-granular |
||||
<filename class="libraryfile">'spring-orm.jar'</filename>.</para> |
||||
|
||||
<para>Spring 2.5's <filename class="libraryfile">'spring-test.jar'</filename> |
||||
supersedes the previous <filename class="libraryfile">'spring-mock.jar'</filename>, |
||||
indicating the stronger focus on the test context framework. |
||||
Note that <filename class="libraryfile">'spring-test.jar'</filename> |
||||
contains everything <filename class="libraryfile">'spring-mock.jar'</filename> |
||||
contained in previous Spring versions; hence it can be used as a |
||||
straightforward replacement for unit and integration testing purposes.</para> |
||||
|
||||
<para>Spring 2.5's <filename class="libraryfile">'spring-tx.jar'</filename> |
||||
supersedes the previous <filename class="libraryfile">'spring-dao.jar'</filename> |
||||
and <filename class="libraryfile">'spring-jca.jar'</filename> files, |
||||
indicating the stronger focus on the transaction framework.</para> |
||||
|
||||
<para>Spring 2.5 ships its framework jars as OSGi-compliant bundles |
||||
out of the box. This facilitates use of Spring in OSGi environments, |
||||
not requiring custom packaging anymore.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-migrating-xml-configuration"> |
||||
<title>XML configuration</title> |
||||
|
||||
<para>Spring 2.0 ships with XSDs that describe Spring's XML metadata |
||||
format in a much richer fashion than the DTD that shipped with |
||||
previous versions. The old DTD is still fully supported, but if |
||||
possible you are encouraged to reference the XSD files at the top of |
||||
your bean definition files.</para> |
||||
|
||||
<para>One thing that has changed in a (somewhat) breaking fashion is |
||||
the way that bean scopes are defined. If you are using the Spring 1.2 |
||||
DTD you can continue to use the <literal>'singleton'</literal> |
||||
attribute. You can however choose to <link |
||||
linkend="new-in-2-ioc-configuration">reference the new Spring 2.0 |
||||
DTD</link> which does not permit the use of the |
||||
<literal>'singleton'</literal> attribute, but rather uses the |
||||
<literal>'scope'</literal> attribute to define the bean lifecycle |
||||
scope.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-migrating-deprecated"> |
||||
<title>Deprecated classes and methods</title> |
||||
|
||||
<para>A number of classes and methods that previously were marked as |
||||
<literal>@deprecated</literal> have been removed from the Spring 2.0 |
||||
codebase. The Spring team decided that the 2.0 release marked a fresh |
||||
start of sorts, and that any deprecated 'cruft' was better excised now |
||||
instead of continuing to haunt the codebase for the foreseeable |
||||
future.</para> |
||||
|
||||
<para>As mentioned previously, for a comprehensive list of changes, |
||||
consult the <filename>'changelog.txt'</filename> file that is located |
||||
in the top level directory of the Spring Framework distribution.</para> |
||||
|
||||
<para>The following classes/interfaces have been removed as of Spring |
||||
2.0:</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<para><interfacename>ResultReader</interfacename> : Use the |
||||
<interfacename>RowMapper</interfacename> interface instead.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><classname>BeanFactoryBootstrap</classname> : Consider using |
||||
a <interfacename>BeanFactoryLocator</interfacename> or a custom |
||||
bootstrap class instead.</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</section> |
||||
|
||||
<section id="new-in-2-migrating-ojb"> |
||||
<title>Apache OJB</title> |
||||
|
||||
<para>As of Spring 2.0, support for Apache OJB was <emphasis>totally |
||||
removed</emphasis> from the main Spring source tree. The Apache OJB |
||||
integration library is still available, but can be found in its new |
||||
home in the <ulink url="https://springmodules.dev.java.net/">Spring |
||||
Modules project</ulink>.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-migrating-ibatis"> |
||||
<title>iBATIS</title> |
||||
|
||||
<para>Please note that support for iBATIS SQL Maps 1.3 has been removed. |
||||
If you haven't done so already, upgrade to iBATIS SQL Maps 2.3.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-migrating-hibernate"> |
||||
<title>Hibernate</title> |
||||
|
||||
<para>As of Spring 2.5, support for Hibernate 2.1 and Hibernate 3.0 |
||||
has been removed. If you haven't done so already, upgrade to |
||||
Hibernate 3.1 or higher.</para> |
||||
|
||||
<para>If you need to stick with Hibernate 2.1 or 3.0 for the time |
||||
being, we recommend to keep using the Spring Framework version |
||||
2.0.7/2.0.8 which still supports those versions of Hibernate.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-migrating-jdo"> |
||||
<title>JDO</title> |
||||
|
||||
<para>As of Spring 2.5, support for JDO 1.0 has been removed. |
||||
If you haven't done so already, upgrade to JDO 2.0 or higher.</para> |
||||
|
||||
<para>If you need to stick with JDO 1.0 for the time being, |
||||
we recommend to keep using the Spring Framework version |
||||
2.0.7/2.0.8 which still supports that version of JDO.</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-migrating-UrlFilenameViewController"> |
||||
<title><classname>UrlFilenameViewController</classname></title> |
||||
|
||||
<para>Since Spring 2.0, the view name that is determined by the |
||||
<classname>UrlFilenameViewController</classname> now takes into |
||||
account the nested path of the request. This is a breaking change |
||||
from the original contract of the |
||||
<classname>UrlFilenameViewController</classname>, and means that if |
||||
you are upgrading from Spring 1.x to Spring 2.x and you are using this |
||||
class you <emphasis>might</emphasis> have to change your Spring Web |
||||
MVC configuration slightly. Refer to the class level Javadocs of the |
||||
<classname>UrlFilenameViewController</classname> to see examples of |
||||
the new contract for view name determination.</para> |
||||
</section> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="new-in-2-other-applications"> |
||||
<title>Updated sample applications</title> |
||||
|
||||
<para>A number of the sample applications have also been updated to |
||||
showcase the new and improved features of Spring 2.0. So do take the time |
||||
to investigate them. The aforementioned sample applications can be found |
||||
in the <filename class="directory">'samples'</filename> directory of the |
||||
full Spring distribution |
||||
(<filename>'spring-with-dependencies.[zip|tar.gz]'</filename>).</para> |
||||
|
||||
<para>Spring 2.5 features revised versions of the PetClinic and PetPortal sample |
||||
applications, reengineered from the ground up for leveraging Spring 2.5's |
||||
annotation configuration features. It also uses Java 5 autoboxing, generics, |
||||
varargs and the enhanced for loop. A Java 5 or 6 SDK is now required to build and |
||||
run the sample. Check out PetClinic and PetPortal to get an impression of what |
||||
Spring 2.5 has to offer!</para> |
||||
</section> |
||||
|
||||
<section id="new-in-2-other-documentation"> |
||||
<title>Improved documentation</title> |
||||
|
||||
<para>The Spring reference documentation has also substantially been |
||||
updated to reflect all of the above features new in Spring 2.0 and 2.5. |
||||
While every effort has been made to ensure that there are no errors in this |
||||
documentation, some errors may nevertheless have crept in. If you do spot |
||||
any typos or even more serious errors, and you can spare a few cycles |
||||
during lunch, please do bring the error to the attention of the Spring |
||||
team by <ulink |
||||
url="http://opensource.atlassian.com/projects/spring/">raising an |
||||
issue</ulink>.</para> |
||||
|
||||
<para>Special thanks to Arthur Loder for his tireless proofreading of the |
||||
Spring Framework reference documentation and JavaDocs.</para> |
||||
</section> |
||||
|
||||
</chapter> |
||||
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<chapter id="new-in-2"> |
||||
<title>What's new in Spring 3.0?</title> |
||||
|
||||
<section id="new-in-3-intro"> |
||||
<title>Introduction</title> |
||||
|
||||
<para>*** WORK IN PROGRESS ***</para> |
||||
|
||||
<para>If you have been using the Spring Framework for some time, you will |
||||
be aware that Spring has undergone two major revisions: Spring 2.0, |
||||
released in October 2006, and Spring 2.5, released in November 2007.</para> |
||||
|
||||
<sidebar id="new-in-3-intro-java"> |
||||
<title>Java SE and Java EE Support</title> |
||||
|
||||
<para>The Spring Framework is now based on Java 5 and Java 6 is fully supported.</para> |
||||
|
||||
<para>Furthermore, Spring is compatible with J2EE 1.4 and Java EE 5, |
||||
while at the same time introducing dedicated support for Java EE 6.</para> |
||||
</sidebar> |
||||
|
||||
</section> |
||||
|
||||
<section id="new-in-3-other-documentation"> |
||||
<title>Improved documentation</title> |
||||
|
||||
<para>The Spring reference documentation has also substantially been |
||||
updated to reflect all of the changes and new features for Spring 3.0. |
||||
While every effort has been made to ensure that there are no errors in this |
||||
documentation, some errors may nevertheless have crept in. If you do spot |
||||
any typos or even more serious errors, and you can spare a few cycles |
||||
during lunch, please do bring the error to the attention of the Spring |
||||
team by <ulink |
||||
url="http://jira.springframework.org/">raising an |
||||
issue</ulink>.</para> |
||||
|
||||
</section> |
||||
|
||||
</chapter> |
||||
@ -0,0 +1,251 @@
@@ -0,0 +1,251 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<chapter id="introduction"> |
||||
<title>Introduction</title> |
||||
|
||||
<sidebar id="background-ioc"> |
||||
<title>Background</title> |
||||
|
||||
<para>In early 2004, Martin Fowler asked the readers of his site: when |
||||
talking about Inversion of Control: <quote><emphasis>the question is, what |
||||
aspect of control are [they] inverting?</emphasis></quote>. Fowler then |
||||
suggested renaming the principle (or at least giving it a more |
||||
self-explanatory name), and started to use the term <firstterm>Dependency |
||||
Injection</firstterm>. His article then continued to explain the ideas |
||||
underpinning the Inversion of Control (<acronym>IoC</acronym>) and |
||||
Dependency Injection (<acronym>DI</acronym>) principle.</para> |
||||
|
||||
<para>If you need a decent insight into IoC and DI, please do refer to |
||||
said article : <ulink |
||||
url="http://martinfowler.com/articles/injection.html">http://martinfowler.com/articles/injection.html</ulink>.</para> |
||||
</sidebar> |
||||
|
||||
<para>Java applications (a loose term which runs the gamut from constrained |
||||
applets to full-fledged n-tier server-side enterprise applications) |
||||
typically are composed of a number of objects that collaborate with one |
||||
another to form the application proper. The objects in an application can |
||||
thus be said to have <emphasis>dependencies</emphasis> between |
||||
themselves.</para> |
||||
|
||||
<para>The Java language and platform provides a wealth of functionality for |
||||
architecting and building applications, ranging all the way from the very |
||||
basic building blocks of primitive types and classes (and the means to |
||||
define new classes), to rich full-featured application servers and web |
||||
frameworks. One area that is decidedly conspicuous by its absence is any |
||||
means of taking the basic building blocks and composing them into a coherent |
||||
whole; this area has typically been left to the purvey of the architects and |
||||
developers tasked with building an application (or applications). Now to be |
||||
fair, there are a number of design patterns devoted to the business of |
||||
composing the various classes and object instances that makeup an |
||||
all-singing, all-dancing application. Design patterns such as |
||||
<firstterm>Factory</firstterm>, <firstterm>Abstract Factory</firstterm>, |
||||
<firstterm>Builder</firstterm>, <firstterm>Decorator</firstterm>, and |
||||
<firstterm>Service Locator</firstterm> (to name but a few) have widespread |
||||
recognition and acceptance within the software development industry |
||||
(presumably that is why these patterns have been formalized as patterns in |
||||
the first place). This is all very well, but these patterns are just that: |
||||
best practices given a name, typically together with a description of what |
||||
the pattern does, where the pattern is typically best applied, the problems |
||||
that the application of the pattern addresses, and so forth. Notice that the |
||||
last paragraph used the phrase <quote>... a <emphasis>description</emphasis> |
||||
of what the pattern does...</quote>; pattern books and wikis are typically |
||||
listings of such formalized best practice that you can certainly take away, |
||||
mull over, and then <emphasis>implement yourself</emphasis> in your |
||||
application.</para> |
||||
|
||||
<para>The IoC component of the Spring Framework addresses the enterprise |
||||
concern of taking the classes, objects, and services that are to compose an |
||||
application, by providing a formalized means of composing these various |
||||
disparate components into a fully working application ready for use. The |
||||
Spring Framework takes best practices that have been proven over the years |
||||
in numerous applications and formalized as design patterns, and actually |
||||
codifies these patterns as first class objects that you as an architect and |
||||
developer can take away and integrate into your own application(s). This is |
||||
a <firstterm>Very Good Thing Indeed</firstterm> as attested to by the |
||||
numerous organizations and institutions that have used the Spring Framework |
||||
to engineer robust, <emphasis>maintainable</emphasis> applications.</para> |
||||
|
||||
<section id="introduction-overview"> |
||||
<title>Overview</title> |
||||
|
||||
<para>The Spring Framework contains a lot of features, which are |
||||
well-organized in six modules shown in the diagram below. This chapter |
||||
discusses each of the modules in turn.</para> |
||||
|
||||
<para><mediaobject> |
||||
<imageobject role="fo"> |
||||
<imagedata align="left" fileref="images/spring-overview.png" |
||||
format="PNG" /> |
||||
</imageobject> |
||||
|
||||
<imageobject role="html"> |
||||
<imagedata align="center" fileref="images/spring-overview.png" |
||||
format="PNG" /> |
||||
</imageobject> |
||||
|
||||
<caption><para>Overview of the Spring Framework</para></caption> |
||||
</mediaobject></para> |
||||
|
||||
<para>The <link |
||||
linkend="beans-introduction"><emphasis>Core</emphasis></link> package is |
||||
the most fundamental part of the framework and provides the IoC and |
||||
Dependency Injection features. The basic concept here is the |
||||
<classname>BeanFactory</classname>, which provides a sophisticated |
||||
implementation of the factory pattern which removes the need for |
||||
programmatic singletons and allows you to decouple the configuration and |
||||
specification of dependencies from your actual program logic.</para> |
||||
|
||||
<para>The <link |
||||
linkend="context-introduction"><emphasis>Context</emphasis></link> package |
||||
build on the solid base provided by the <link |
||||
linkend="beans-introduction"><emphasis>Core</emphasis></link> package: it |
||||
provides a way to access objects in a framework-style manner in a fashion |
||||
somewhat reminiscent of a JNDI-registry. The context package inherits its |
||||
features from the beans package and adds support for internationalization |
||||
(I18N) (using for example resource bundles), event-propagation, |
||||
resource-loading, and the transparent creation of contexts by, for |
||||
example, a servlet container.</para> |
||||
|
||||
<para>The <link linkend="dao-introduction"><emphasis>DAO</emphasis></link> |
||||
package provides a JDBC-abstraction layer that removes the need to do |
||||
tedious JDBC coding and parsing of database-vendor specific error codes. |
||||
Also, the <link linkend="jdbc-introduction">JDBC</link> package provides a |
||||
way to do programmatic as well as declarative transaction management, not |
||||
only for classes implementing special interfaces, but for <emphasis>all |
||||
your POJOs (plain old Java objects)</emphasis>.</para> |
||||
|
||||
<para>The <link linkend="orm-introduction"><emphasis>ORM</emphasis></link> |
||||
package provides integration layers for popular object-relational mapping |
||||
APIs, including <link linkend="orm-jpa">JPA</link>, <link |
||||
linkend="orm-jdo">JDO</link>, <link |
||||
linkend="orm-hibernate">Hibernate</link>, and <link |
||||
linkend="orm-ibatis">iBatis</link>. Using the ORM package you can use all |
||||
those O/R-mappers in combination with all the other features Spring |
||||
offers, such as the simple declarative transaction management feature |
||||
mentioned previously.</para> |
||||
|
||||
<para>Spring's <link |
||||
linkend="aop-introduction"><emphasis>AOP</emphasis></link> package |
||||
provides an <emphasis>AOP Alliance</emphasis>-compliant aspect-oriented |
||||
programming implementation allowing you to define, for example, |
||||
method-interceptors and pointcuts to cleanly decouple code implementing |
||||
functionality that should logically speaking be separated. Using |
||||
source-level metadata functionality you can also incorporate all kinds of |
||||
behavioral information into your code, in a manner similar to that of .NET |
||||
attributes.</para> |
||||
|
||||
<para>Spring's <emphasis>Web</emphasis> package provides basic |
||||
web-oriented integration features, such as multipart file-upload |
||||
functionality, the initialization of the IoC container using servlet |
||||
listeners and a web-oriented application context. When using Spring |
||||
together with WebWork or Struts, this is the package to integrate |
||||
with.</para> |
||||
|
||||
<para>Spring's <link |
||||
linkend="mvc-introduction"><emphasis>MVC</emphasis></link> package |
||||
provides a Model-View-Controller (MVC) implementation for |
||||
web-applications. Spring's MVC framework is not just any old |
||||
implementation; it provides a <emphasis>clean</emphasis> separation |
||||
between domain model code and web forms, and allows you to use all the |
||||
other features of the Spring Framework.</para> |
||||
</section> |
||||
|
||||
<section id="overview-usagescenarios"> |
||||
<title>Usage scenarios</title> |
||||
|
||||
<para>With the building blocks described above you can use Spring in all |
||||
sorts of scenarios, from applets up to fully-fledged enterprise |
||||
applications using Spring's transaction management functionality and web |
||||
framework integration.</para> |
||||
|
||||
<para><mediaobject> |
||||
<imageobject role="fo"> |
||||
<imagedata align="center" fileref="images/full.png" format="PNG" /> |
||||
</imageobject> |
||||
|
||||
<imageobject role="html"> |
||||
<imagedata align="center" fileref="images/full.gif" format="GIF" /> |
||||
</imageobject> |
||||
|
||||
<caption><para>Typical full-fledged Spring web |
||||
application</para></caption> |
||||
</mediaobject></para> |
||||
|
||||
<para>By using Spring's <link |
||||
linkend="transaction-declarative">declarative transaction management |
||||
features</link> the web application is fully transactional, just as it |
||||
would be when using container managed transactions as provided by |
||||
Enterprise JavaBeans. All your custom business logic can be implemented |
||||
using simple POJOs, managed by Spring's IoC container. Additional services |
||||
include support for sending email, and validation that is independent of |
||||
the web layer enabling you to choose where to execute validation rules. |
||||
Spring's ORM support is integrated with JPA, Hibernate, JDO and iBatis; |
||||
for example, when using Hibernate, you can continue to use your existing |
||||
mapping files and standard Hibernate |
||||
<interfacename>SessionFactory</interfacename> configuration. Form |
||||
controllers seamlessly integrate the web-layer with the domain model, |
||||
removing the need for <classname>ActionForms</classname> or other classes |
||||
that transform HTTP parameters to values for your domain model.</para> |
||||
|
||||
<para><mediaobject> |
||||
<imageobject role="fo"> |
||||
<imagedata align="center" fileref="images/thirdparty-web.png" |
||||
format="PNG" /> |
||||
</imageobject> |
||||
|
||||
<imageobject role="html"> |
||||
<imagedata align="center" fileref="images/thirdparty-web.gif" |
||||
format="GIF" /> |
||||
</imageobject> |
||||
|
||||
<caption><para>Spring middle-tier using a third-party web |
||||
framework</para></caption> |
||||
</mediaobject></para> |
||||
|
||||
<para>Sometimes the current circumstances do not allow you to completely |
||||
switch to a different framework. The Spring Framework does |
||||
<emphasis>not</emphasis> force you to use everything within it; it is not |
||||
an <emphasis>all-or-nothing</emphasis> solution. Existing front-ends built |
||||
using WebWork, Struts, Tapestry, or other UI frameworks can be integrated |
||||
perfectly well with a Spring-based middle-tier, allowing you to use the |
||||
transaction features that Spring offers. The only thing you need to do is |
||||
wire up your business logic using an |
||||
<classname>ApplicationContext</classname> and integrate your web layer |
||||
using a <classname>WebApplicationContext</classname>.</para> |
||||
|
||||
<para><mediaobject> |
||||
<imageobject role="fo"> |
||||
<imagedata align="center" fileref="images/remoting.png" format="PNG" /> |
||||
</imageobject> |
||||
|
||||
<imageobject role="html"> |
||||
<imagedata align="center" fileref="images/remoting.gif" format="GIF" /> |
||||
</imageobject> |
||||
|
||||
<caption><para>Remoting usage scenario</para></caption> |
||||
</mediaobject></para> |
||||
|
||||
<para>When you need to access existing code via web services, you can use |
||||
Spring's <literal>Hessian-</literal>, <literal>Burlap-</literal>, |
||||
<literal>Rmi-</literal> or <classname>JaxRpcProxyFactory</classname> |
||||
classes. Enabling remote access to existing applications suddenly is not |
||||
that hard anymore.</para> |
||||
|
||||
<para><mediaobject> |
||||
<imageobject role="fo"> |
||||
<imagedata align="center" fileref="images/ejb.png" format="PNG" /> |
||||
</imageobject> |
||||
|
||||
<imageobject role="html"> |
||||
<imagedata align="center" fileref="images/ejb.gif" format="GIF" /> |
||||
</imageobject> |
||||
|
||||
<caption><para>EJBs - Wrapping existing POJOs</para></caption> |
||||
</mediaobject></para> |
||||
|
||||
<para>The Spring Framework also provides an <link linkend="ejb">access- |
||||
and abstraction- layer</link> for Enterprise JavaBeans, enabling you to |
||||
reuse your existing POJOs and wrap them in Stateless Session Beans, for |
||||
use in scalable, failsafe web applications that might need declarative |
||||
security.</para> |
||||
</section> |
||||
</chapter> |
||||
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<preface id="preface"> |
||||
<title>Preface</title> |
||||
|
||||
<para>Developing software applications is hard enough even with good tools |
||||
and technologies. Implementing applications using platforms which promise |
||||
everything but turn out to be heavy-weight, hard to control and not very |
||||
efficient during the development cycle makes it even harder. Spring provides |
||||
a light-weight solution for building enterprise-ready applications, while |
||||
still supporting the possibility of using declarative transaction |
||||
management, remote access to your logic using RMI or web services, and |
||||
various options for persisting your data to a database. Spring provides a |
||||
full-featured <link linkend="mvc-introduction">MVC framework</link>, and |
||||
transparent ways of integrating <link linkend="aop-introduction">AOP</link> |
||||
into your software.</para> |
||||
|
||||
<para>Spring could potentially be a one-stop-shop for all your enterprise |
||||
applications; however, Spring is modular, allowing you to use just those |
||||
parts of it that you need, without having to bring in the rest. You can use |
||||
the IoC container, with Struts on top, but you could also choose to use just |
||||
the <link linkend="orm-hibernate">Hibernate integration code</link> or the |
||||
<link linkend="jdbc-introduction">JDBC abstraction layer</link>. Spring has |
||||
been (and continues to be) designed to be non-intrusive, meaning |
||||
dependencies on the framework itself are generally none (or absolutely |
||||
minimal, depending on the area of use).</para> |
||||
|
||||
<para>This document provides a reference guide to Spring's features. Since |
||||
this document is still to be considered very much work-in-progress, if you |
||||
have any requests or comments, please post them on the user mailing list or |
||||
on the support forums at <ulink |
||||
url="http://forum.springframework.org/" />.</para> |
||||
|
||||
<para>Before we go on, a few words of gratitude are due to Christian Bauer |
||||
(of the <ulink url="http://www.hibernate.org/">Hibernate</ulink> team), who |
||||
prepared and adapted the DocBook-XSL software in order to be able to create |
||||
Hibernate's reference guide, thus also allowing us to create this one. Also |
||||
thanks to Russell Healy for doing an extensive and valuable review of some |
||||
of the material.</para> |
||||
</preface> |
||||
@ -0,0 +1,739 @@
@@ -0,0 +1,739 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<chapter id="resources"> |
||||
<title>Resources</title> |
||||
|
||||
<section id="resources-introduction"> |
||||
<title>Introduction</title> |
||||
|
||||
<para>Java's standard <classname>java.net.URL</classname> class and |
||||
standard handlers for various URL prefixes unfortunately are not quite |
||||
adequate enough for all access to low-level resources. For example, |
||||
there is no standardized <classname>URL</classname> implementation |
||||
that may be used to access a resource that needs to be obtained from |
||||
the classpath, or relative to a |
||||
<interfacename>ServletContext</interfacename>. While it is possible |
||||
to register new handlers for specialized <classname>URL</classname> |
||||
prefixes (similar to existing handlers for prefixes such as |
||||
<literal>http:</literal>), this is generally quite complicated, and the |
||||
<classname>URL</classname> interface still lacks some desirable |
||||
functionality, such as a method to check for the existence of the |
||||
resource being pointed to.</para> |
||||
</section> |
||||
|
||||
<section id="resources-resource"> |
||||
<title>The <interfacename>Resource</interfacename> interface</title> |
||||
|
||||
<para>Spring's <interfacename>Resource</interfacename> interface is meant |
||||
to be a more capable interface for abstracting access to low-level |
||||
resources.</para> |
||||
|
||||
<programlisting><![CDATA[public interface Resource extends InputStreamSource { |
||||
|
||||
boolean exists(); |
||||
|
||||
boolean isOpen(); |
||||
|
||||
URL getURL() throws IOException; |
||||
|
||||
File getFile() throws IOException; |
||||
|
||||
Resource createRelative(String relativePath) throws IOException; |
||||
|
||||
String getFilename(); |
||||
|
||||
String getDescription(); |
||||
}]]></programlisting> |
||||
|
||||
<programlisting><![CDATA[public interface InputStreamSource { |
||||
|
||||
InputStream getInputStream() throws IOException; |
||||
}]]></programlisting> |
||||
|
||||
<para>Some of the most important methods from the |
||||
<interfacename>Resource</interfacename> interface are:</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<para><methodname>getInputStream()</methodname>: locates and opens the |
||||
resource, returning an <classname>InputStream</classname> for reading |
||||
from the resource. It is expected that each invocation returns a |
||||
fresh <classname>InputStream</classname>. It is the responsibility of |
||||
the caller to close the stream.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><methodname>exists()</methodname>: returns a |
||||
<literal>boolean</literal> indicating whether this resource actually |
||||
exists in physical form.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><methodname>isOpen()</methodname>: returns a |
||||
<literal>boolean</literal> indicating whether this resource represents |
||||
a handle with an open stream. If <literal>true</literal>, the |
||||
<classname>InputStream</classname> cannot be read multiple times, and |
||||
must be read once only and then closed to avoid resource leaks. Will |
||||
be <literal>false</literal> for all usual resource implementations, |
||||
with the exception of |
||||
<classname>InputStreamResource</classname>.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><methodname>getDescription()</methodname>: returns a description |
||||
for this resource, to be used for error output when working with the |
||||
resource. This is often the fully qualified file name or the actual |
||||
URL of the resource.</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
|
||||
<para>Other methods allow you to obtain an actual |
||||
<classname>URL</classname> or <classname>File</classname> object |
||||
representing the resource (if the underlying implementation is compatible, |
||||
and supports that functionality).</para> |
||||
|
||||
<para>The <interfacename>Resource</interfacename> abstraction is used |
||||
extensively in Spring itself, as an argument type in many method |
||||
signatures when a resource is needed. Other methods in some Spring APIs |
||||
(such as the constructors to various |
||||
<interfacename>ApplicationContext</interfacename> implementations), take a |
||||
<classname>String</classname> which in unadorned or simple form is used to |
||||
create a <interfacename>Resource</interfacename> appropriate to that |
||||
context implementation, or via special prefixes on the |
||||
<classname>String</classname> path, allow the caller to specify that a |
||||
specific <interfacename>Resource</interfacename> implementation must be |
||||
created and used.</para> |
||||
|
||||
<para>While the <interfacename>Resource</interfacename> interface is used |
||||
a lot with Spring and by Spring, it's actually very useful to use as a |
||||
general utility class by itself in your own code, for access to resources, |
||||
even when your code doesn't know or care about any other parts of Spring. |
||||
While this couples your code to Spring, it really only couples it to this |
||||
small set of utility classes, which are serving as a more capable |
||||
replacement for <classname>URL</classname>, and can be considered |
||||
equivalent to any other library you would use for this purpose.</para> |
||||
|
||||
<para>It is important to note that the |
||||
<interfacename>Resource</interfacename> abstraction does not replace |
||||
functionality: it wraps it where possible. For example, a |
||||
<classname>UrlResource</classname> wraps a URL, and uses the wrapped |
||||
<classname>URL</classname> to do its work.</para> |
||||
</section> |
||||
|
||||
<section id="resources-implementations"> |
||||
<title>Built-in <interfacename>Resource</interfacename> implementations</title> |
||||
|
||||
<para>There are a number of <interfacename>Resource</interfacename> |
||||
implementations that come supplied straight out of the box in |
||||
Spring:</para> |
||||
|
||||
<section id="resources-implementations-urlresource"> |
||||
<title><classname>UrlResource</classname></title> |
||||
|
||||
<para>The <classname>UrlResource</classname> wraps a |
||||
<classname>java.net.URL</classname>, and may be used to access any |
||||
object that is normally accessible via a URL, such as files, an HTTP |
||||
target, an FTP target, etc. All URLs have a standardized |
||||
<classname>String</classname> representation, such that appropriate |
||||
standardized prefixes are used to indicate one URL type from another. |
||||
This includes <literal>file:</literal> for accessing filesystem paths, |
||||
<literal>http:</literal> for accessing resources via the HTTP protocol, |
||||
<literal>ftp:</literal> for accessing resources via FTP, etc.</para> |
||||
|
||||
<para>A <classname>UrlResource</classname> is created by Java code |
||||
explicitly using the <classname>UrlResource</classname> constructor, but |
||||
will often be created implicitly when you call an API method which takes |
||||
a <classname>String</classname> argument which is meant to represent a |
||||
path. For the latter case, a JavaBeans |
||||
<interfacename>PropertyEditor</interfacename> will ultimately decide |
||||
which type of <interfacename>Resource</interfacename> to create. If the |
||||
path string contains a few well-known (to it, that is) prefixes such as |
||||
<literal>classpath:</literal>, it will create an appropriate specialized |
||||
<interfacename>Resource</interfacename> for that prefix. However, if it |
||||
doesn't recognize the prefix, it will assume the this is just a standard |
||||
URL string, and will create a <classname>UrlResource</classname>.</para> |
||||
</section> |
||||
|
||||
<section id="resources-implementations-classpathresource"> |
||||
<title><classname>ClassPathResource</classname></title> |
||||
|
||||
<para>This class represents a resource which should be obtained from the |
||||
classpath. This uses either the thread context class loader, a given |
||||
class loader, or a given class for loading resources.</para> |
||||
|
||||
<para>This <interfacename>Resource</interfacename> implementation |
||||
supports resolution as <classname>java.io.File</classname> if the class |
||||
path resource resides in the file system, but not for classpath |
||||
resources which reside in a jar and have not been expanded (by the |
||||
servlet engine, or whatever the environment is) to the filesystem. To |
||||
address this the various <interfacename>Resource</interfacename> |
||||
implementations always support resolution as a |
||||
<classname>java.net.URL</classname>.</para> |
||||
|
||||
<para>A <classname>ClassPathResource</classname> is created by Java code |
||||
explicitly using the <classname>ClassPathResource</classname> |
||||
constructor, but will often be created implicitly when you call an API |
||||
method which takes a <classname>String</classname> argument which is |
||||
meant to represent a path. For the latter case, a JavaBeans |
||||
<interfacename>PropertyEditor</interfacename> will recognize the special |
||||
prefix <literal>classpath:</literal>on the string path, and create a |
||||
<classname>ClassPathResource</classname> in that case.</para> |
||||
</section> |
||||
|
||||
<section id="resources-implementations-filesystemresource"> |
||||
<title><classname>FileSystemResource</classname></title> |
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation |
||||
for <classname>java.io.File</classname> handles. It obviously supports |
||||
resolution as a <classname>File</classname>, and as a |
||||
<classname>URL</classname>.</para> |
||||
</section> |
||||
|
||||
<section id="resources-implementations-servletcontextresource"> |
||||
<title><classname>ServletContextResource</classname></title> |
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation |
||||
for <interfacename>ServletContext</interfacename> resources, |
||||
interpreting relative paths within the relevant web application's root |
||||
directory.</para> |
||||
|
||||
<para>This always supports stream access and URL access, but only allows |
||||
<classname>java.io.File</classname> access when the web application |
||||
archive is expanded and the resource is physically on the filesystem. |
||||
Whether or not it's expanded and on the filesystem like this, or |
||||
accessed directly from the JAR or somewhere else like a DB (it's |
||||
conceivable) is actually dependent on the Servlet container.</para> |
||||
</section> |
||||
|
||||
<section id="resources-implementations-inputstreamresource"> |
||||
<title><classname>InputStreamResource</classname></title> |
||||
|
||||
<para>A <interfacename>Resource</interfacename> implementation for a |
||||
given <interfacename>InputStream</interfacename>. This should only be |
||||
used if no specific <interfacename>Resource</interfacename> |
||||
implementation is applicable. In particular, prefer |
||||
<classname>ByteArrayResource</classname> or any of the file-based |
||||
<interfacename>Resource</interfacename> implementations where |
||||
possible.</para> |
||||
|
||||
<para>In contrast to other <interfacename>Resource</interfacename> |
||||
implementations, this is a descriptor for an |
||||
<emphasis>already</emphasis> opened resource - therefore returning |
||||
<literal>true</literal> from <methodname>isOpen()</methodname>. Do not |
||||
use it if you need to keep the resource descriptor somewhere, or if you |
||||
need to read a stream multiple times.</para> |
||||
</section> |
||||
|
||||
<section id="resources-implementations-bytearrayresource"> |
||||
<title><classname>ByteArrayResource</classname></title> |
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation |
||||
for a given byte array. It creates a |
||||
<classname>ByteArrayInputStream</classname> for the given byte |
||||
array.</para> |
||||
|
||||
<para>It's useful for loading content from any given byte array, without |
||||
having to resort to a single-use |
||||
<classname>InputStreamResource</classname>.</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="resources-resourceloader"> |
||||
<title>The <interfacename>ResourceLoader</interfacename></title> |
||||
|
||||
<para>The <interfacename>ResourceLoader</interfacename> interface is meant |
||||
to be implemented by objects that can return (i.e. load) |
||||
<interfacename>Resource</interfacename> instances.</para> |
||||
|
||||
<programlisting>public interface ResourceLoader { |
||||
Resource getResource(String location); |
||||
}</programlisting> |
||||
|
||||
<para>All application contexts implement the |
||||
<interfacename>ResourceLoader</interfacename> interface, and therefore all |
||||
application contexts may be used to obtain |
||||
<interfacename>Resource</interfacename> instances.</para> |
||||
|
||||
<para>When you call <methodname>getResource()</methodname> on a specific |
||||
application context, and the location path specified doesn't have a |
||||
specific prefix, you will get back a |
||||
<interfacename>Resource</interfacename> type that is appropriate to that |
||||
particular application context. For example, assume the following snippet |
||||
of code was executed against a |
||||
<classname>ClassPathXmlApplicationContext</classname> instance:</para> |
||||
|
||||
<programlisting>Resource template = ctx.getResource("some/resource/path/myTemplate.txt);</programlisting> |
||||
|
||||
<para>What would be returned would be a |
||||
<classname>ClassPathResource</classname>; if the same method was executed |
||||
against a <classname>FileSystemXmlApplicationContext</classname> instance, |
||||
you'd get back a <classname>FileSystemResource</classname>. For a |
||||
<classname>WebApplicationContext</classname>, you'd get back a |
||||
<classname>ServletContextResource</classname>, and so on.</para> |
||||
|
||||
<para>As such, you can load resources in a fashion appropriate to the |
||||
particular application context.</para> |
||||
|
||||
<para>On the other hand, you may also force |
||||
<classname>ClassPathResource</classname> to be used, regardless of the |
||||
application context type, by specifying the special |
||||
<literal>classpath:</literal> prefix:</para> |
||||
|
||||
<programlisting>Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt);</programlisting> |
||||
|
||||
<para>Similarly, one can force a <classname>UrlResource</classname> to be |
||||
used by specifying any of the standard <classname>java.net.URL</classname> |
||||
prefixes:</para> |
||||
|
||||
<programlisting>Resource template = ctx.getResource("file:/some/resource/path/myTemplate.txt);</programlisting> |
||||
|
||||
<programlisting>Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt);</programlisting> |
||||
|
||||
<para>The following table summarizes the strategy for converting |
||||
<classname>String</classname>s to |
||||
<interfacename>Resource</interfacename>s:</para> |
||||
|
||||
<table pgwide="1" id="resources-resource-strings"> |
||||
<title>Resource strings</title> |
||||
|
||||
<tgroup cols="3"> |
||||
<colspec align="left" /> |
||||
|
||||
<thead> |
||||
<row> |
||||
<entry align="center">Prefix</entry> |
||||
|
||||
<entry align="center">Example</entry> |
||||
|
||||
<entry align="center">Explanation</entry> |
||||
</row> |
||||
</thead> |
||||
|
||||
<tbody> |
||||
<row> |
||||
<entry><para>classpath:</para></entry> |
||||
|
||||
<entry><para> <literal>classpath:com/myapp/config.xml</literal> |
||||
</para></entry> |
||||
|
||||
<entry><para>Loaded from the classpath.</para></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><para>file:</para></entry> |
||||
|
||||
<entry><para> <literal>file:/data/config.xml</literal> |
||||
</para></entry> |
||||
|
||||
<entry><para> Loaded as a <classname>URL</classname>, from the |
||||
filesystem. <footnote> |
||||
<para>But see also the section entitled <xref |
||||
linkend="resources-filesystemresource-caveats" />.</para> |
||||
</footnote> </para></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><para>http:</para></entry> |
||||
|
||||
<entry><para> <literal>http://myserver/logo.png</literal> |
||||
</para></entry> |
||||
|
||||
<entry><para>Loaded as a |
||||
<classname>URL</classname>.</para></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><para>(none)</para></entry> |
||||
|
||||
<entry><para> <literal>/data/config.xml</literal> </para></entry> |
||||
|
||||
<entry><para> Depends on the underlying |
||||
<interfacename>ApplicationContext</interfacename>. </para></entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
</section> |
||||
|
||||
<section id="resources-resourceloaderaware"> |
||||
<title>The <interfacename>ResourceLoaderAware</interfacename> interface</title> |
||||
|
||||
<para>The <interfacename>ResourceLoaderAware</interfacename> interface is |
||||
a special marker interface, identifying objects that expect to be provided |
||||
with a <interfacename>ResourceLoader</interfacename> reference.</para> |
||||
|
||||
<programlisting><![CDATA[public interface ResourceLoaderAware { |
||||
|
||||
void setResourceLoader(ResourceLoader resourceLoader); |
||||
}]]></programlisting> |
||||
|
||||
<para>When a class implements |
||||
<interfacename>ResourceLoaderAware</interfacename> and is deployed into an |
||||
application context (as a Spring-managed bean), it is recognized as |
||||
<interfacename>ResourceLoaderAware</interfacename> by the application |
||||
context. The application context will then invoke the |
||||
<methodname>setResourceLoader(ResourceLoader)</methodname>, supplying |
||||
itself as the argument (remember, all application contexts in Spring |
||||
implement the <interfacename>ResourceLoader</interfacename> |
||||
interface).</para> |
||||
|
||||
<para>Of course, since an |
||||
<interfacename>ApplicationContext</interfacename> is a |
||||
<interfacename>ResourceLoader</interfacename>, the bean could also |
||||
implement the <interfacename>ApplicationContextAware</interfacename> |
||||
interface and use the supplied application context directly to load |
||||
resources, but in general, it's better to use the specialized |
||||
<interfacename>ResourceLoader</interfacename> interface if that's all |
||||
that's needed. The code would just be coupled to the resource loading |
||||
interface, which can be considered a utility interface, and not the whole |
||||
Spring <interfacename>ApplicationContext</interfacename> interface.</para> |
||||
|
||||
<para>As of Spring 2.5, you can rely upon autowiring of the |
||||
<interfacename>ResourceLoader</interfacename> as an alternative to |
||||
implementing the <interfacename>ResourceLoaderAware</interfacename> interface. |
||||
The "traditional" <literal>constructor</literal> and <literal>byType</literal> |
||||
autowiring modes (as described in the section entitled |
||||
<xref linkend="beans-factory-autowire"/>) are now capable of providing a |
||||
dependency of type <interfacename>ResourceLoader</interfacename> for either a |
||||
constructor argument or setter method parameter respectively. For more flexibility |
||||
(including the ability to autowire fields and multiple parameter methods), consider |
||||
using the new annotation-based autowiring features. In that case, the |
||||
<interfacename>ResourceLoader</interfacename> will be autowired into a field, |
||||
constructor argument, or method parameter that is expecting the |
||||
<interfacename>ResourceLoader</interfacename> type as long as the field, |
||||
constructor, or method in question carries the |
||||
<interfacename>@Autowired</interfacename> annotation. For more information, |
||||
see the section entitled <xref linkend="beans-autowired-annotation"/>.</para> |
||||
</section> |
||||
|
||||
<section id="resources-as-dependencies"> |
||||
<title><literal>Resources</literal> as dependencies</title> |
||||
|
||||
<para>If the bean itself is going to determine and supply the resource |
||||
path through some sort of dynamic process, it probably makes sense for the |
||||
bean to use the <interfacename>ResourceLoader</interfacename> interface to |
||||
load resources. Consider as an example the loading of a template of some |
||||
sort, where the specific resource that is needed depends on the role of |
||||
the user. If the resources are static, it makes sense to eliminate the use |
||||
of the <interfacename>ResourceLoader</interfacename> interface completely, |
||||
and just have the bean expose the <interfacename>Resource</interfacename> |
||||
properties it needs, and expect that they will be injected into it.</para> |
||||
|
||||
<para>What makes it trivial to then inject these properties, is that all |
||||
application contexts register and use a special JavaBeans |
||||
<interfacename>PropertyEditor</interfacename> which can convert |
||||
<classname>String</classname> paths to |
||||
<interfacename>Resource</interfacename> objects. So if |
||||
<literal>myBean</literal> has a template property of type |
||||
<interfacename>Resource</interfacename>, it can be configured with a |
||||
simple string for that resource, as follows:</para> |
||||
|
||||
<programlisting><![CDATA[<bean id="myBean" class="..."> |
||||
<property name="template" value="some/resource/path/myTemplate.txt"/> |
||||
</bean>]]></programlisting> |
||||
|
||||
<para>Note that the resource path has no prefix, so because the |
||||
application context itself is going to be used as the |
||||
<interfacename>ResourceLoader</interfacename>, the resource itself will be |
||||
loaded via a <classname>ClassPathResource</classname>, |
||||
<literal>FileSystemResource</literal>, or |
||||
<classname>ServletContextResource</classname> (as appropriate) |
||||
depending on the exact type of the context.</para> |
||||
|
||||
<para>If there is a need to force a specific |
||||
<interfacename>Resource</interfacename> type to be used, then a prefix may |
||||
be used. The following two examples show how to force a |
||||
<classname>ClassPathResource</classname> and a |
||||
<classname>UrlResource</classname> (the latter being used to access a |
||||
filesystem file).</para> |
||||
|
||||
<programlisting><![CDATA[<property name="template" value="classpath:some/resource/path/myTemplate.txt">]]></programlisting> |
||||
|
||||
<programlisting><![CDATA[<property name="template" value="file:/some/resource/path/myTemplate.txt"/>]]></programlisting> |
||||
</section> |
||||
|
||||
<section id="resources-app-ctx"> |
||||
<title>Application contexts and <interfacename>Resource</interfacename> paths</title> |
||||
|
||||
<section id="resources-app-ctx-construction"> |
||||
<title>Constructing application contexts</title> |
||||
|
||||
<para>An application context constructor (for a specific application |
||||
context type) generally takes a string or array of strings as the |
||||
location path(s) of the resource(s) such as XML files that make up the |
||||
definition of the context.</para> |
||||
|
||||
<para>When such a location path doesn't have a prefix, the specific |
||||
<interfacename>Resource</interfacename> type built from that path and |
||||
used to load the bean definitions, depends on and is appropriate to the |
||||
specific application context. For example, if you create a |
||||
<classname>ClassPathXmlApplicationContext</classname> as follows:</para> |
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");]]></programlisting> |
||||
|
||||
<para>The bean definitions will be loaded from the classpath, as a |
||||
<classname></classname><classname>ClassPathResource</classname> will be |
||||
used. But if you create a |
||||
<classname>FileSystemXmlApplicationContext</classname> as |
||||
follows:</para> |
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx = |
||||
new FileSystemXmlApplicationContext("conf/appContext.xml");]]></programlisting> |
||||
|
||||
<para>The bean definition will be loaded from a filesystem location, in |
||||
this case relative to the current working directory.</para> |
||||
|
||||
<para>Note that the use of the special classpath prefix or a standard |
||||
URL prefix on the location path will override the default type of |
||||
<interfacename>Resource</interfacename> created to load the definition. |
||||
So this <classname>FileSystemXmlApplicationContext</classname>...</para> |
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx = |
||||
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");]]></programlisting> |
||||
|
||||
<para>... will actually load its bean definitions from the classpath. |
||||
However, it is still a <classname>FileSystemXmlApplicationContext</classname>. If it is |
||||
subsequently used as a <interfacename>ResourceLoader</interfacename>, |
||||
any unprefixed paths will still be treated as filesystem paths.</para> |
||||
|
||||
<section id="resources-app-ctx-classpathxml"> |
||||
<title>Constructing <classname>ClassPathXmlApplicationContext</classname> instances - shortcuts</title> |
||||
|
||||
<para>The <classname>ClassPathXmlApplicationContext</classname> |
||||
exposes a number of constructors to enable convenient instantiation. |
||||
The basic idea is that one supplies merely a string array containing |
||||
just the filenames of the XML files themselves (without the leading |
||||
path information), and one <emphasis>also</emphasis> supplies a |
||||
<classname>Class</classname>; the |
||||
<classname>ClassPathXmlApplicationContext</classname> will derive the |
||||
path information from the supplied class.</para> |
||||
|
||||
<para>An example will hopefully make this clear. Consider a directory |
||||
layout that looks like this:</para> |
||||
|
||||
<programlisting><![CDATA[com/ |
||||
foo/ |
||||
services.xml |
||||
daos.xml |
||||
MessengerService.class]]></programlisting> |
||||
|
||||
<para>A <classname>ClassPathXmlApplicationContext</classname> instance |
||||
composed of the beans defined in the <literal>'services.xml'</literal> |
||||
and <literal>'daos.xml'</literal> could be instantiated like |
||||
so...</para> |
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx = new ClassPathXmlApplicationContext( |
||||
new String[] {"services.xml", "daos.xml"}, MessengerService.class);]]></programlisting> |
||||
|
||||
<para>Please do consult the Javadocs for the |
||||
<classname>ClassPathXmlApplicationContext</classname> class for |
||||
details of the various constructors.</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="resources-app-ctx-wildcards-in-resource-paths"> |
||||
<title>Wildcards in application context constructor resource paths</title> |
||||
|
||||
<para>The resource paths in application context constructor values may |
||||
be a simple path (as shown above) which has a one-to-one mapping to a |
||||
target Resource, or alternately may contain the special "classpath*:" |
||||
prefix and/or internal Ant-style regular expressions (matched using |
||||
Spring's <classname>PathMatcher</classname> utility). Both of the latter |
||||
are effectively wildcards</para> |
||||
|
||||
<para>One use for this mechanism is when doing component-style |
||||
application assembly. All components can 'publish' context definition |
||||
fragments to a well-known location path, and when the final application |
||||
context is created using the same path prefixed via |
||||
<literal>classpath*:</literal>, all component fragments will be picked |
||||
up automatically.</para> |
||||
|
||||
<para>Note that this wildcarding is specific to use of resource paths in |
||||
application context constructors (or when using the |
||||
<classname>PathMatcher</classname> utility class hierarchy directly), |
||||
and is resolved at construction time. It has nothing to do with the |
||||
<interfacename>Resource</interfacename> type itself. It's not possible |
||||
to use the <literal>classpath*:</literal> prefix to construct an actual |
||||
<interfacename>Resource</interfacename>, as a resource points to just |
||||
one resource at a time.</para> |
||||
|
||||
<section id="resources-app-ctx-ant-patterns-in-paths"> |
||||
<title>Ant-style Patterns</title> |
||||
|
||||
<para>When the path location contains an Ant-style pattern, for example:</para> |
||||
|
||||
<programlisting><![CDATA[ /WEB-INF/*-context.xml |
||||
com/mycompany/**/applicationContext.xml |
||||
file:C:/some/path/*-context.xml |
||||
classpath:com/mycompany/**/applicationContext.xml]]></programlisting> |
||||
|
||||
<para>... the resolver follows a more complex but defined procedure to |
||||
try to resolve the wildcard. It produces a Resource for the path up to |
||||
the last non-wildcard segment and obtains a URL from it. If this URL |
||||
is not a "jar:" URL or container-specific variant (e.g. |
||||
"<literal>zip:</literal>" in WebLogic, "<literal>wsjar</literal>" in |
||||
WebSphere, etc.), then a <classname>java.io.File</classname> is |
||||
obtained from it and used to resolve the wildcard by traversing the |
||||
filesystem. In the case of a jar URL, the resolver either gets a |
||||
<classname>java.net.JarURLConnection</classname> from it or manually |
||||
parses the jar URL and then traverses the contents of the jar file |
||||
to resolve the wildcards.</para> |
||||
|
||||
<section id="resources-app-ctx-portability"> |
||||
<title>Implications on portability</title> |
||||
|
||||
<para>If the specified path is already a file URL (either |
||||
explicitly, or implicitly because the base |
||||
<interfacename>ResourceLoader</interfacename> is a |
||||
filesystem one, then wildcarding is guaranteed to work in a |
||||
completely portable fashion.</para> |
||||
|
||||
<para>If the specified path is a classpath location, then the |
||||
resolver must obtain the last non-wildcard path segment URL via a |
||||
<methodname>Classloader.getResource()</methodname> call. Since this |
||||
is just a node of the path (not the file at the end) it is actually |
||||
undefined (in the <classname>ClassLoader</classname> Javadocs) |
||||
exactly what sort of a URL is returned in this case. In practice, it |
||||
is always a <classname>java.io.File</classname> representing the |
||||
directory, where the classpath resource resolves to a filesystem |
||||
location, or a jar URL of some sort, where the classpath resource |
||||
resolves to a jar location. Still, there is a portability concern on |
||||
this operation.</para> |
||||
|
||||
<para>If a jar URL is obtained for the last non-wildcard segment, |
||||
the resolver must be able to get a |
||||
<classname>java.net.JarURLConnection</classname> from it, or |
||||
manually parse the jar URL, to be able to walk the contents of the |
||||
jar, and resolve the wildcard. This will work in most environments, |
||||
but will fail in others, and it is strongly recommended that the |
||||
wildcard resolution of resources coming from jars be thoroughly |
||||
tested in your specific environment before you rely on it.</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="resources-classpath-wildcards"> |
||||
<title>The <literal>classpath*:</literal> prefix</title> |
||||
|
||||
<para>When constructing an XML-based application context, a location |
||||
string may use the special <literal>classpath*:</literal> |
||||
prefix:</para> |
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx = |
||||
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");]]></programlisting> |
||||
|
||||
<para>This special prefix specifies that all classpath resources that |
||||
match the given name must be obtained (internally, this essentially |
||||
happens via a <methodname>ClassLoader.getResources(...)</methodname> |
||||
call), and then merged to form the final application context |
||||
definition.</para> |
||||
|
||||
<note> |
||||
<title>Classpath*: portability</title> |
||||
|
||||
<para>The wildcard classpath relies on the <literal>getResources()</literal> method of the |
||||
underlying classloader. As most application servers nowadays supply |
||||
their own classloader implementation, the behavior might differ |
||||
especially when dealing with jar files. A simple test to check if |
||||
<literal>classpath*</literal> works is to use the classloader to load a file from |
||||
within a jar on the classpath: |
||||
<literal>getClass().getClassLoader().getResources("<someFileInsideTheJar>")</literal>. |
||||
Try this test with files that have the same name but are placed |
||||
inside two different locations. In case an inappropriate result is |
||||
returned, check the application server documentation for settings |
||||
that might affect the classloader behavior.</para> |
||||
</note> |
||||
|
||||
<para>The "<literal>classpath*:</literal>" prefix can also be combined |
||||
with a <literal>PathMatcher</literal> pattern in the rest of the location path, for |
||||
example "<literal>classpath*:META-INF/*-beans.xml</literal>". In this |
||||
case, the resolution strategy is fairly simple: a |
||||
ClassLoader.getResources() call is used on the last non-wildcard path |
||||
segment to get all the matching resources in the class loader |
||||
hierarchy, and then off each resource the same PathMatcher resoltion |
||||
strategy described above is used for the wildcard subpath.</para> |
||||
</section> |
||||
|
||||
<section id="resources-wildcards-in-path-other-stuff"> |
||||
<title>Other notes relating to wildcards</title> |
||||
|
||||
<para>Please note that "<literal>classpath*:</literal>" when |
||||
combined with Ant-style patterns will only work reliably with at least |
||||
one root directory before the pattern starts, unless the actual target |
||||
files reside in the file system. This means that a pattern like |
||||
"<literal>classpath*:*.xml</literal>" will not retrieve files from the |
||||
root of jar files but rather only from the root of expanded |
||||
directories. This originates from a limitation in the JDK's |
||||
<methodname>ClassLoader.getResources()</methodname> method which only |
||||
returns file system locations for a passed-in empty string (indicating |
||||
potential roots to search).</para> |
||||
|
||||
<para>Ant-style patterns with "<literal>classpath:</literal>" |
||||
resources are not guaranteed to find matching resources if the root |
||||
package to search is available in multiple class path locations. This |
||||
is because a resource such as</para> |
||||
|
||||
<programlisting><![CDATA[ com/mycompany/package1/service-context.xml]]></programlisting> |
||||
|
||||
<para>may be in only one location, but when a path such as</para> |
||||
|
||||
<programlisting><![CDATA[ classpath:com/mycompany/**/service-context.xml]]></programlisting> |
||||
|
||||
<para>is used to try to resolve it, the resolver will work off the (first) URL |
||||
returned by <methodname>getResource("com/mycompany")</methodname>;. If |
||||
this base package node exists in multiple classloader locations, the |
||||
actual end resource may not be underneath. Therefore, preferably, use |
||||
"<literal>classpath*:</literal>" with the same Ant-style pattern in |
||||
such a case, which will search all class path locations that contain |
||||
the root package.</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="resources-filesystemresource-caveats"> |
||||
<title><classname>FileSystemResource</classname> caveats</title> |
||||
|
||||
<para>A <classname>FileSystemResource</classname> that is not attached |
||||
to a <classname>FileSystemApplicationContext</classname> (that is, a |
||||
<classname>FileSystemApplicationContext</classname> is not the actual |
||||
<interfacename>ResourceLoader</interfacename>) will treat absolute vs. |
||||
relative paths as you would expect. Relative paths are relative to the |
||||
current working directory, while absolute paths are relative to the root |
||||
of the filesystem.</para> |
||||
|
||||
<para>For backwards compatibility (historical) reasons however, this |
||||
changes when the <classname>FileSystemApplicationContext</classname> is |
||||
the <literal>ResourceLoader</literal>. The |
||||
<classname>FileSystemApplicationContext</classname> simply forces all |
||||
attached <classname>FileSystemResource</classname> instances to treat |
||||
all location paths as relative, whether they start with a leading slash |
||||
or not. In practice, this means the following are equivalent:</para> |
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx = |
||||
new FileSystemXmlApplicationContext("conf/context.xml");]]></programlisting> |
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx = |
||||
new FileSystemXmlApplicationContext("/conf/context.xml");]]></programlisting> |
||||
|
||||
<para>As are the following: (Even though it would make sense for them to |
||||
be different, as one case is relative and the other absolute.)</para> |
||||
|
||||
<programlisting><![CDATA[FileSystemXmlApplicationContext ctx = ...; |
||||
ctx.getResource("some/resource/path/myTemplate.txt");]]></programlisting> |
||||
|
||||
<programlisting><![CDATA[FileSystemXmlApplicationContext ctx = ...; |
||||
ctx.getResource("/some/resource/path/myTemplate.txt");]]></programlisting> |
||||
|
||||
<para>In practice, if true absolute filesystem paths are needed, it is |
||||
better to forgo the use of absolute paths with |
||||
<classname>FileSystemResource</classname> / |
||||
<classname>FileSystemXmlApplicationContext</classname>, and just force |
||||
the use of a <classname>UrlResource</classname>, by using the |
||||
<literal>file:</literal> URL prefix.</para> |
||||
|
||||
<programlisting><lineannotation>// actual context type doesn't matter, the <interfacename>Resource</interfacename> will always be <classname>UrlResource</classname></lineannotation><![CDATA[ |
||||
ctx.getResource("file:/some/resource/path/myTemplate.txt");]]></programlisting> |
||||
|
||||
<programlisting><lineannotation>// force this FileSystemXmlApplicationContext to load its definition via a <classname>UrlResource</classname></lineannotation><![CDATA[ |
||||
ApplicationContext ctx = |
||||
new FileSystemXmlApplicationContext("file:/conf/context.xml");]]></programlisting> |
||||
</section> |
||||
</section> |
||||
</chapter> |
||||
@ -0,0 +1,499 @@
@@ -0,0 +1,499 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<chapter id="scheduling"> |
||||
<title>Scheduling and Thread Pooling</title> |
||||
<section id="scheduling-introduction"> |
||||
<title>Introduction</title> |
||||
<para> |
||||
The Spring Framework features integration classes for scheduling support. Currently, Spring |
||||
supports the <classname>Timer</classname>, part of the JDK since 1.3, and the |
||||
Quartz Scheduler (<ulink url="http://www.opensymphony.com/quartz/"/>). Both schedulers |
||||
are set up using a <interfacename>FactoryBean</interfacename> with optional references |
||||
to <classname>Timer</classname> or <classname>Trigger</classname> instances, respectively. |
||||
Furthermore, a convenience class for both the Quartz Scheduler and the <classname>Timer</classname> is |
||||
available that allows you to invoke a method of an existing target object |
||||
(analogous to the normal <classname>MethodInvokingFactoryBean</classname> operation). |
||||
Spring also features classes for thread pooling that abstract |
||||
away differences between Java SE 1.4, Java SE 5 and Java EE environments. |
||||
</para> |
||||
</section> |
||||
<section id="scheduling-quartz"> |
||||
<title>Using the OpenSymphony Quartz Scheduler</title> |
||||
<para>Quartz uses <classname>Trigger</classname>, <classname>Job</classname> and |
||||
<classname>JobDetail</classname> objects to realize scheduling of all kinds of jobs. |
||||
For the basic concepts behind Quartz, have a look at |
||||
<ulink url="http://www.opensymphony.com/quartz" />. For convenience purposes, |
||||
Spring offers a couple of classes that simplify the usage of Quartz within |
||||
Spring-based applications. |
||||
</para> |
||||
<section id="scheduling-quartz-jobdetail"> |
||||
<title>Using the JobDetailBean</title> |
||||
<para> |
||||
<classname>JobDetail</classname> objects contain all information needed to |
||||
run a job. The Spring Framework provides a <classname>JobDetailBean</classname> |
||||
that makes the <classname>JobDetail</classname> more of an actual JavaBean |
||||
with sensible defaults. Let's have a look at an example: |
||||
</para> |
||||
<programlisting><![CDATA[ |
||||
<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailBean"> |
||||
<property name="jobClass" value="example.ExampleJob" /> |
||||
<property name="jobDataAsMap"> |
||||
<map> |
||||
<entry key="timeout" value="5" /> |
||||
</map> |
||||
</property> |
||||
</bean>]]></programlisting> |
||||
<para>The job detail bean has all information it needs to run the job (<classname>ExampleJob</classname>). |
||||
The timeout is specified in the job data map. The job data map is |
||||
available through the <classname>JobExecutionContext</classname> |
||||
(passed to you at execution time), but the <classname>JobDetailBean</classname> |
||||
also maps the properties from the job data map to properties of the actual job. |
||||
So in this case, if the <classname>ExampleJob</classname> contains a property |
||||
named <literal>timeout</literal>, the <classname>JobDetailBean</classname> will |
||||
automatically apply it:</para> |
||||
<programlisting><![CDATA[package example; |
||||
|
||||
public class ExampleJob extends QuartzJobBean { |
||||
|
||||
private int timeout; |
||||
|
||||
/** |
||||
* Setter called after the ExampleJob is instantiated |
||||
* with the value from the JobDetailBean (5) |
||||
*/ |
||||
public void setTimeout(int timeout) { |
||||
this.timeout = timeout; |
||||
} |
||||
|
||||
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException { |
||||
]]><lineannotation>// do the actual work</lineannotation><![CDATA[ |
||||
} |
||||
}]]></programlisting> |
||||
<para>All additional settings from the job detail bean are of course available to you as well.</para> |
||||
<para><emphasis>Note: Using the <literal>name</literal> and <literal>group</literal> properties, |
||||
you can modify the name and the group of the job, respectively. By default, the name of |
||||
the job matches the bean name of the job detail bean (in the example above, this is |
||||
<literal>exampleJob</literal>).</emphasis></para> |
||||
</section> |
||||
<section id="scheduling-quartz-method-invoking-job"> |
||||
<title>Using the <classname>MethodInvokingJobDetailFactoryBean</classname></title> |
||||
<para>Often you just need to invoke a method on a specific object. Using the |
||||
<classname>MethodInvokingJobDetailFactoryBean</classname> you can do exactly this:</para> |
||||
<programlisting><![CDATA[<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> |
||||
<property name="targetObject" ref="exampleBusinessObject" /> |
||||
<property name="targetMethod" value="doIt" /> |
||||
</bean>]]></programlisting> |
||||
<para>The above example will result in the <literal>doIt</literal> method being called on the |
||||
<literal>exampleBusinessObject</literal> method (see below):</para> |
||||
<programlisting><![CDATA[public class ExampleBusinessObject { |
||||
|
||||
]]><lineannotation>// properties and collaborators</lineannotation><![CDATA[ |
||||
|
||||
public void doIt() { |
||||
]]><lineannotation>// do the actual work</lineannotation><![CDATA[ |
||||
} |
||||
}]]></programlisting> |
||||
|
||||
<programlisting><![CDATA[ |
||||
<bean id="exampleBusinessObject" class="examples.ExampleBusinessObject"/>]]></programlisting> |
||||
<para>Using the <classname>MethodInvokingJobDetailFactoryBean</classname>, you don't need to |
||||
create one-line jobs that just invoke a method, and you only need to create the actual |
||||
business object and wire up the detail object.</para> |
||||
<para>By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering |
||||
with each other. If you specify two triggers for the same <classname>JobDetail</classname>, |
||||
it might be possible that before the first job has finished, the second one will start. |
||||
If <classname>JobDetail</classname> classes implement the |
||||
<interfacename>Stateful</interfacename> interface, this won't happen. The second job |
||||
will not start before the first one has finished. To make jobs resulting from the |
||||
<classname>MethodInvokingJobDetailFactoryBean</classname> non-concurrent, set the |
||||
<literal>concurrent</literal> flag to <literal>false</literal>.</para> |
||||
<programlisting><![CDATA[ |
||||
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> |
||||
<property name="targetObject" ref="exampleBusinessObject" /> |
||||
<property name="targetMethod" value="doIt" /> |
||||
<property name="concurrent" value="false" /> |
||||
</bean>]]></programlisting> |
||||
<note> |
||||
<para>By default, jobs will run in a concurrent fashion.</para> |
||||
</note> |
||||
</section> |
||||
<section id="scheduling-quartz-cron"> |
||||
<title>Wiring up jobs using triggers and the <classname>SchedulerFactoryBean</classname></title> |
||||
<para> |
||||
We've created job details and jobs. We've also reviewed the convenience bean |
||||
that allows to you invoke a method on a specific object. Of course, we still need |
||||
to schedule the jobs themselves. This is done using triggers and a |
||||
<classname>SchedulerFactoryBean</classname>. Several triggers are available |
||||
within Quartz. Spring offers two subclassed triggers with convenient defaults: |
||||
<classname>CronTriggerBean</classname> and <classname>SimpleTriggerBean</classname>. |
||||
</para> |
||||
<para> |
||||
Triggers need to be scheduled. Spring offers a <classname>SchedulerFactoryBean</classname> |
||||
that exposes triggers to be set as properties. <classname>SchedulerFactoryBean</classname> |
||||
schedules the actual jobs with those triggers. |
||||
</para> |
||||
<para>Find below a couple of examples:</para> |
||||
<programlisting><![CDATA[<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> |
||||
<!-- see the example of method invoking job above --> |
||||
<property name="jobDetail" ref="jobDetail" /> |
||||
<!-- 10 seconds --> |
||||
<property name="startDelay" value="10000" /> |
||||
<!-- repeat every 50 seconds --> |
||||
<property name="repeatInterval" value="50000" /> |
||||
</bean> |
||||
|
||||
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> |
||||
<property name="jobDetail" ref="exampleJob" /> |
||||
<!-- run every morning at 6 AM --> |
||||
<property name="cronExpression" value="0 0 6 * * ?" /> |
||||
</bean>]]></programlisting> |
||||
<para>Now we've set up two triggers, one running every 50 seconds with a starting delay of |
||||
10 seconds and one every morning at 6 AM. To finalize everything, we need to set up the |
||||
<classname>SchedulerFactoryBean</classname>:</para> |
||||
<programlisting><![CDATA[<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> |
||||
<property name="triggers"> |
||||
<list> |
||||
<ref bean="cronTrigger" /> |
||||
<ref bean="simpleTrigger" /> |
||||
</list> |
||||
</property> |
||||
</bean>]]></programlisting> |
||||
<para> |
||||
More properties are available for the <classname>SchedulerFactoryBean</classname> for you |
||||
to set, such as the calendars used by the job details, properties to customize Quartz with, |
||||
etc. Have a look at the |
||||
<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/scheduling/quartz/SchedulerFactoryBean.html">SchedulerFactoryBean Javadoc</ulink> |
||||
for more information. |
||||
</para> |
||||
</section> |
||||
</section> |
||||
<section id="scheduling-jdk-timer"> |
||||
<title>Using JDK Timer support</title> |
||||
<para> |
||||
The other way to schedule jobs in Spring is to use JDK |
||||
<classname>Timer</classname> objects. You can create custom timers or |
||||
use the timer that invokes methods. Wiring timers is done using the |
||||
<classname>TimerFactoryBean</classname>. |
||||
</para> |
||||
<section id="scheduling-jdk-timer-creating"> |
||||
<title>Creating custom timers</title> |
||||
<para> |
||||
Using the <classname>TimerTask</classname> you can create customer |
||||
timer tasks, similar to Quartz jobs: |
||||
</para> |
||||
<programlisting><![CDATA[public class CheckEmailAddresses extends TimerTask { |
||||
|
||||
private List emailAddresses; |
||||
|
||||
public void setEmailAddresses(List emailAddresses) { |
||||
this.emailAddresses = emailAddresses; |
||||
} |
||||
|
||||
public void run() { |
||||
]]><lineannotation>// iterate over all email addresses and archive them</lineannotation><![CDATA[ |
||||
} |
||||
}]]></programlisting> |
||||
<para> |
||||
Wiring it up is simple: |
||||
</para> |
||||
<programlisting><![CDATA[<bean id="checkEmail" class="examples.CheckEmailAddress"> |
||||
<property name="emailAddresses"> |
||||
<list> |
||||
<value>test@springframework.org</value> |
||||
<value>foo@bar.com</value> |
||||
<value>john@doe.net</value> |
||||
</list> |
||||
</property> |
||||
</bean> |
||||
|
||||
<bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask"> |
||||
]]><lineannotation><!-- wait 10 seconds before starting repeated execution --></lineannotation><![CDATA[ |
||||
<property name="delay" value="10000" /> |
||||
]]><lineannotation><!-- run every 50 seconds --></lineannotation><![CDATA[ |
||||
<property name="period" value="50000" /> |
||||
<property name="timerTask" ref="checkEmail" /> |
||||
</bean>]]></programlisting> |
||||
<para> |
||||
<emphasis> |
||||
Note that letting the task only run once can be done by changing the |
||||
<literal>period</literal> property to 0 (or a negative value). |
||||
</emphasis> |
||||
</para> |
||||
</section> |
||||
<section id="scheduling-jdk-timer-method-invoking-task"> |
||||
<title>Using the <classname>MethodInvokingTimerTaskFactoryBean</classname></title> |
||||
<para> |
||||
Similar to the Quartz support, the <classname>Timer</classname> support also features |
||||
a component that allows you to periodically invoke a method: |
||||
</para> |
||||
<programlisting><![CDATA[<bean id="doIt" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"> |
||||
<property name="targetObject" ref="exampleBusinessObject" /> |
||||
<property name="targetMethod" value="doIt" /> |
||||
</bean>]]></programlisting> |
||||
<para> |
||||
The above example will result in the <literal>doIt</literal> method being called on the |
||||
<literal>exampleBusinessObject</literal> (see below): |
||||
</para> |
||||
<programlisting><![CDATA[public class BusinessObject { |
||||
|
||||
]]><lineannotation>// properties and collaborators</lineannotation><![CDATA[ |
||||
|
||||
public void doIt() { |
||||
]]><lineannotation>// do the actual work</lineannotation><![CDATA[ |
||||
} |
||||
}]]></programlisting> |
||||
<para>Changing the <literal>timerTask</literal> reference of the |
||||
<classname>ScheduledTimerTask</classname> example to the bean <literal>doIt</literal> |
||||
will result in the <literal>doIt</literal> method being executed on a fixed schedule.</para> |
||||
</section> |
||||
<section id="scheduling-jdk-timer-factory-bean"> |
||||
<title>Wrapping up: setting up the tasks using the <classname>TimerFactoryBean</classname></title> |
||||
<para>The <classname>TimerFactoryBean</classname> is similar to the Quartz |
||||
<classname>SchedulerFactoryBean</classname> in that it serves the same |
||||
purpose: setting up the actual scheduling. The <classname>TimerFactoryBean</classname> |
||||
sets up an actual <classname>Timer</classname> and schedules the tasks it has |
||||
references to. You can specify whether or not daemon threads should be used.</para> |
||||
<programlisting><![CDATA[<bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean"> |
||||
<property name="scheduledTimerTasks"> |
||||
<list> |
||||
]]><lineannotation><!-- see the example above --></lineannotation><![CDATA[ |
||||
<ref bean="scheduledTask" /> |
||||
</list> |
||||
</property> |
||||
</bean>]]></programlisting> |
||||
</section> |
||||
</section> |
||||
<section id="scheduling-task-executor"> |
||||
<title>The Spring <interfacename>TaskExecutor</interfacename> abstraction</title> |
||||
<para>Spring 2.0 introduces a new abstraction for dealing with |
||||
executors. Executors are the Java 5 name for the concept of |
||||
thread pools. The "executor" naming is due to the fact that there |
||||
is no guarantee that the underlying implementation is actually a |
||||
pool; an executor may be single-threaded or even synchronous. |
||||
Spring's abstraction hides implementation details between |
||||
Java SE 1.4, Java SE 5 and Java EE environments.</para> |
||||
<title>The <interfacename>TaskExecutor</interfacename> interface</title> |
||||
<para>Spring's <interfacename>TaskExecutor</interfacename> interface is |
||||
identical to the <classname>java.util.concurrent.Executor</classname> |
||||
interface. In fact, its primary reason for existence is to abstract away |
||||
the need for Java 5 when using thread pools. The interface has a single |
||||
method <classname>execute(Runnable task)</classname> that accepts a task |
||||
for execution based on the semantics and configuration of the thread pool.</para> |
||||
<para>The <interfacename>TaskExecutor</interfacename> was originally |
||||
created to give other Spring components an abstraction for thread pooling where |
||||
needed. Components such as the <classname>ApplicationEventMulticaster</classname>, |
||||
JMS's <classname>AbstractMessageListenerContainer</classname>, |
||||
and Quartz integration all use the <interfacename>TaskExecutor</interfacename> |
||||
abstraction to pool threads. However, if your beans need thread pooling behavior, |
||||
it is possible to use this abstraction for your own needs.</para> |
||||
|
||||
<section id="scheduling-task-executor-types"> |
||||
<title><interfacename>TaskExecutor</interfacename> types</title> |
||||
<para>There are a number of pre-built implementations of |
||||
<interfacename>TaskExecutor</interfacename> included with the |
||||
Spring distribution. In all likelihood, you shouldn't ever |
||||
need to implement your own.</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<para> |
||||
<classname>SimpleAsyncTaskExecutor</classname> |
||||
</para> |
||||
|
||||
<para> |
||||
This implementation does not reuse any threads, |
||||
rather it starts up a new thread for each |
||||
invocation. However, it does support a |
||||
concurrency limit which will block any |
||||
invocations that are over the limit until a slot |
||||
has been freed up. If you're looking for true |
||||
pooling, keep scrolling further down the page. |
||||
</para> |
||||
</listitem> |
||||
|
||||
<listitem id="syncTaskExecutor"> |
||||
<para> |
||||
<classname>SyncTaskExecutor</classname> |
||||
</para> |
||||
|
||||
<para> |
||||
This implementation doesn't execute |
||||
invocations asynchronously. Instead, each |
||||
invocation takes place in the calling thread. It |
||||
is primarily used in situations where |
||||
mutlithreading isn't necessary such as simple |
||||
test cases. |
||||
</para> |
||||
</listitem> |
||||
|
||||
<listitem id="concurrentTaskExecutor"> |
||||
<para> |
||||
<classname>ConcurrentTaskExecutor</classname> |
||||
</para> |
||||
|
||||
<para> |
||||
This implementation is a wrapper for a Java 5 |
||||
<classname>java.util.concurrent.Executor</classname>. |
||||
There is an alternative, |
||||
<classname>ThreadPoolTaskExecutor</classname>, |
||||
that exposes the <classname>Executor</classname> |
||||
configuration parameters as bean properties. It |
||||
is rare to need to use the <classname>ConcurrentTaskExecutor</classname> |
||||
but if the |
||||
<link linkend="threadPoolTaskExecutor"><classname>ThreadPoolTaskExecutor</classname></link> |
||||
isn't robust enough for your needs, the |
||||
<classname>ConcurrentTaskExecutor</classname> |
||||
is an alternative. |
||||
</para> |
||||
</listitem> |
||||
|
||||
<listitem id="simpleThreadPoolTaskExecutor"> |
||||
<para> |
||||
<classname>SimpleThreadPoolTaskExecutor</classname> |
||||
</para> |
||||
|
||||
<para> |
||||
This implementation is actually a subclass of |
||||
Quartz's <classname>SimpleThreadPool</classname> |
||||
which listens to Spring's lifecycle callbacks. |
||||
This is typically used when you have a |
||||
threadpool that may need to be shared by both |
||||
Quartz and non-Quartz components. |
||||
</para> |
||||
</listitem> |
||||
|
||||
<listitem id="threadPoolTaskExecutor"> |
||||
<para> |
||||
<classname>ThreadPoolTaskExecutor</classname> |
||||
</para> |
||||
|
||||
<sidebar> |
||||
<para> |
||||
It is not possible to use any backport or |
||||
alternate versions of the |
||||
<classname>java.util.concurrent</classname> |
||||
package with this implementation. Both Doug |
||||
Lea's and Dawid Kurzyniec's implementations |
||||
use different package structures which will |
||||
prevent them from working correctly. |
||||
</para> |
||||
</sidebar> |
||||
|
||||
<para> |
||||
This implementation can only be used in a Java 5 |
||||
environment but is also the most commonly used |
||||
one in that environment. It exposes bean properties for |
||||
configuring a |
||||
<classname>java.util.concurrent.ThreadPoolExecutor</classname> |
||||
and wraps it in a <interfacename>TaskExecutor</interfacename>. |
||||
If you need something advanced such as a |
||||
<classname>ScheduledThreadPoolExecutor</classname>, |
||||
it is recommended that you use a |
||||
<link linkend="concurrentTaskExecutor"><classname>ConcurrentTaskExecutor</classname></link> |
||||
instead. |
||||
</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para> |
||||
<classname>TimerTaskExecutor</classname> |
||||
</para> |
||||
|
||||
<para> |
||||
This implementation uses a single |
||||
<classname>TimerTask</classname> |
||||
as its backing implementation. It's different |
||||
from the |
||||
<link linkend="syncTaskExecutor"><classname>SyncTaskExecutor</classname></link> |
||||
in that the method invocations are executed in a |
||||
separate thread, although they are synchronous |
||||
in that thread. |
||||
</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para> |
||||
<classname>WorkManagerTaskExecutor</classname> |
||||
</para> |
||||
|
||||
<sidebar><para> |
||||
CommonJ is a set of specifications jointly |
||||
developed between BEA and IBM. These |
||||
specifications are not Java EE standards, but |
||||
are standard across BEA's and IBM's |
||||
Application Server implementations. |
||||
</para></sidebar> |
||||
|
||||
<para> |
||||
This implementation uses the CommonJ WorkManager |
||||
as its backing implementation and is the central |
||||
convenience class for setting up a CommonJ |
||||
WorkManager reference in a Spring context. |
||||
Similar to the |
||||
<link linkend="simpleThreadPoolTaskExecutor"><classname>SimpleThreadPoolTaskExecutor</classname></link>, |
||||
this class implements the WorkManager |
||||
interface and therefore can be used directly as |
||||
a WorkManager as well. |
||||
</para> |
||||
</listitem> |
||||
|
||||
</itemizedlist> |
||||
</section> |
||||
<section id="scheduling-task-executor-usage"> |
||||
<title>Using a <interfacename>TaskExecutor</interfacename></title> |
||||
<para>Spring's <interfacename>TaskExecutor</interfacename> implementations |
||||
are used as simple JavaBeans. In the example below, we define |
||||
a bean that uses the <classname>ThreadPoolTaskExecutor</classname> |
||||
to asynchronously print out a set of messages.</para> |
||||
|
||||
<programlisting><![CDATA[import org.springframework.core.task.TaskExecutor; |
||||
|
||||
public class TaskExecutorExample { |
||||
|
||||
private class MessagePrinterTask implements Runnable { |
||||
|
||||
private String message; |
||||
|
||||
public MessagePrinterTask(String message) { |
||||
this.message = message; |
||||
} |
||||
|
||||
public void run() { |
||||
System.out.println(message); |
||||
} |
||||
|
||||
} |
||||
|
||||
private TaskExecutor taskExecutor; |
||||
|
||||
public TaskExecutorExample(TaskExecutor taskExecutor) { |
||||
this.taskExecutor = taskExecutor; |
||||
} |
||||
|
||||
public void printMessages() { |
||||
for(int i = 0; i < 25; i++) { |
||||
taskExecutor.execute(new MessagePrinterTask("Message" + i)); |
||||
} |
||||
} |
||||
}]]></programlisting> |
||||
|
||||
<para>As you can see, rather than retrieving a thread from the |
||||
pool and executing yourself, you add your <classname>Runnable</classname> |
||||
to the queue and the <interfacename>TaskExecutor</interfacename> |
||||
uses its internal rules to decide when the task gets executed.</para> |
||||
|
||||
<para>To configure the rules that the <interfacename>TaskExecutor</interfacename> |
||||
will use, simple bean properties have been exposed.</para> |
||||
|
||||
<programlisting><![CDATA[<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> |
||||
<property name="corePoolSize" value="5" /> |
||||
<property name="maxPoolSize" value="10" /> |
||||
<property name="queueCapacity" value="25" /> |
||||
</bean> |
||||
|
||||
<bean id="taskExecutorExample" class="TaskExecutorExample"> |
||||
<constructor-arg ref="taskExecutor" /> |
||||
</bean>]]></programlisting> |
||||
|
||||
</section> |
||||
</section> |
||||
</chapter> |
||||
@ -0,0 +1,346 @@
@@ -0,0 +1,346 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" |
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [ |
||||
<!ENTITY preface SYSTEM "preface.xml"> |
||||
<!ENTITY overview SYSTEM "overview.xml"> |
||||
<!ENTITY whats-new-in-3 SYSTEM "new-in-3.xml"> |
||||
<!ENTITY beans SYSTEM "beans.xml"> |
||||
<!ENTITY resources SYSTEM "resources.xml"> |
||||
<!ENTITY validation SYSTEM "validation.xml"> |
||||
<!ENTITY aop SYSTEM "aop.xml"> |
||||
<!ENTITY aop-api SYSTEM "aop-api.xml"> |
||||
<!ENTITY transaction SYSTEM "transaction.xml"> |
||||
<!ENTITY metadata SYSTEM "metadata.xml"> |
||||
<!ENTITY dao SYSTEM "dao.xml"> |
||||
<!ENTITY jdbc SYSTEM "jdbc.xml"> |
||||
<!ENTITY orm SYSTEM "orm.xml"> |
||||
<!ENTITY mvc SYSTEM "mvc.xml"> |
||||
<!ENTITY view SYSTEM "view.xml"> |
||||
<!ENTITY web-integration SYSTEM "web-integration.xml"> |
||||
<!ENTITY portlet SYSTEM "portlet.xml"> |
||||
<!ENTITY remoting SYSTEM "remoting.xml"> |
||||
<!ENTITY ejb SYSTEM "ejb.xml"> |
||||
<!ENTITY jms SYSTEM "jms.xml"> |
||||
<!ENTITY jmx SYSTEM "jmx.xml"> |
||||
<!ENTITY cci SYSTEM "cci.xml"> |
||||
<!ENTITY mail SYSTEM "mail.xml"> |
||||
<!ENTITY scheduling SYSTEM "scheduling.xml"> |
||||
<!ENTITY testing SYSTEM "testing.xml"> |
||||
<!ENTITY dynamic-languages SYSTEM "dynamic-languages.xml"> |
||||
<!ENTITY xsd-configuration SYSTEM "xsd-configuration.xml"> |
||||
<!ENTITY xml-custom SYSTEM "xml-custom.xml"> |
||||
<!ENTITY dtd SYSTEM "dtd.xml"> |
||||
<!ENTITY spring-tld SYSTEM "spring.tld.xml"> |
||||
<!ENTITY spring-form-tld SYSTEM "spring-form.tld.xml"> |
||||
<!ENTITY swf-sidebar SYSTEM "swf-sidebar.xml"> |
||||
]> |
||||
<book> |
||||
<bookinfo> |
||||
<title>Reference Documentation</title> |
||||
<subtitle>(Work in progress)</subtitle> |
||||
<productname>Spring Framework</productname> |
||||
<releaseinfo>3.0.M3</releaseinfo> |
||||
<mediaobject> |
||||
<imageobject role="fo"> |
||||
<imagedata align="center" fileref="images/logo-pdf.png" |
||||
format="PNG" width="240"/> |
||||
</imageobject> |
||||
</mediaobject> |
||||
<authorgroup> |
||||
<author> |
||||
<firstname>Rod</firstname> |
||||
<surname>Johnson</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Juergen</firstname> |
||||
<surname>Hoeller</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Alef</firstname> |
||||
<surname>Arendsen</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Colin</firstname> |
||||
<surname>Sampaleanu</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Rob</firstname> |
||||
<surname>Harrop</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Thomas</firstname> |
||||
<surname>Risberg</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Darren</firstname> |
||||
<surname>Davison</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Dmitriy</firstname> |
||||
<surname>Kopylenko</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Mark</firstname> |
||||
<surname>Pollack</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Thierry</firstname> |
||||
<surname>Templier</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Erwin</firstname> |
||||
<surname>Vervaet</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Portia</firstname> |
||||
<surname>Tung</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Ben</firstname> |
||||
<surname>Hale</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Adrian</firstname> |
||||
<surname>Colyer</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>John</firstname> |
||||
<surname>Lewis</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Costin</firstname> |
||||
<surname>Leau</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Mark</firstname> |
||||
<surname>Fisher</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Sam</firstname> |
||||
<surname>Brannen</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Ramnivas</firstname> |
||||
<surname>Laddad</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Arjen</firstname> |
||||
<surname>Poutsma</surname> |
||||
</author> |
||||
</authorgroup> |
||||
<copyright> |
||||
<year>2004-2009</year> |
||||
<holder>Rod Johnson, Juergen Hoeller, Alef Arendsen, Colin Sampaleanu, Rob Harrop, Thomas Risberg, Darren Davison, |
||||
Dmitriy Kopylenko, Mark Pollack, Thierry Templier, Erwin Vervaet, Portia Tung, Ben Hale, Adrian Colyer, John Lewis, Costin Leau, |
||||
Mark Fisher, Sam Brannen, Ramnivas Laddad, Arjen Poutsma |
||||
</holder> |
||||
</copyright> |
||||
<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> |
||||
<!-- front matter --> |
||||
<toc/> |
||||
&preface; |
||||
&overview; |
||||
&whats-new-in-3; |
||||
<part id="spring-core"> |
||||
<title>Core Technologies</title> |
||||
<partintro id="spring-core-intro"> |
||||
<para> |
||||
This initial part of the reference documentation covers |
||||
all of those technologies that are absolutely integral |
||||
to the Spring Framework. |
||||
</para> |
||||
<para> |
||||
Foremost amongst these is the Spring Framework's |
||||
Inversion of Control (IoC) container. A thorough treatment |
||||
of the Spring Framework's IoC container is closely followed |
||||
by comprehensive coverage of Spring's Aspect-Oriented |
||||
Programming (AOP) technologies. The Spring Framework has |
||||
its own AOP framework, which is conceptually easy to understand, |
||||
and which successfully addresses the 80% sweet spot of AOP |
||||
requirements in Java enterprise programming. |
||||
</para> |
||||
<para> |
||||
Coverage of Spring's integration with AspectJ (currently |
||||
the richest - in terms of features - and certainly most |
||||
mature AOP implementation in the Java enterprise space) |
||||
is also provided. |
||||
</para> |
||||
<para> |
||||
Finally, the adoption of the test-driven-development (TDD) |
||||
approach to software development is certainly advocated by |
||||
the Spring team, and so coverage of Spring's support for |
||||
integration testing is covered (alongside best practices for |
||||
unit testing). The Spring team have found that the correct |
||||
use of IoC certainly does make both unit and integration |
||||
testing easier (in that the presence of setter methods and |
||||
appropriate constructors on classes makes them |
||||
easier to wire together on a test without having to set up |
||||
service locator registries and suchlike)... the chapter |
||||
dedicated solely to testing will hopefully convince you of |
||||
this as well. |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para><xref linkend="beans"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="resources"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="validation"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="aop"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="aop-api"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="testing"/></para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</partintro> |
||||
&beans; |
||||
&resources; |
||||
&validation; |
||||
&aop; |
||||
&aop-api; |
||||
&testing; |
||||
</part> |
||||
<part id="spring-middle-tier"> |
||||
<title>Middle Tier Data Access</title> |
||||
<partintro id="spring-middle-tier-intro"> |
||||
<para> |
||||
This part of the reference documentation is concerned |
||||
with the middle tier, and specifically the data access |
||||
responsibilities of said tier. |
||||
</para> |
||||
<para> |
||||
Spring's comprehensive transaction management support is |
||||
covered in some detail, followed by thorough coverage of |
||||
the various middle tier data access frameworks and |
||||
technologies that the Spring Framework integrates with. |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para><xref linkend="transaction"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="dao"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="jdbc"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="orm"/></para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</partintro> |
||||
&transaction; |
||||
&dao; |
||||
&jdbc; |
||||
&orm; |
||||
</part> |
||||
<part id="spring-web"> |
||||
<title>The Web</title> |
||||
<partintro id="spring-web-intro"> |
||||
<para> |
||||
This part of the reference documentation covers the |
||||
Spring Framework's support for the presentation tier |
||||
(and specifically web-based presentation tiers). |
||||
</para> |
||||
<para> |
||||
The Spring Framework's own web framework, |
||||
<link linkend="mvc">Spring Web MVC</link>, is covered in |
||||
the first couple of chapters. A number of the remaining |
||||
chapters in this part of the reference documentation are |
||||
concerned with the Spring Framework's integration with |
||||
other web technologies, such as <link linkend="struts">Struts</link> |
||||
and <link linkend="jsf">JSF</link> (to name but two). |
||||
</para> |
||||
<para> |
||||
This section concludes with coverage of Spring's MVC |
||||
<link linkend="portlet">portlet framework</link>. |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para><xref linkend="mvc"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="view"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="web-integration"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="portlet"/></para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</partintro> |
||||
&mvc; |
||||
&view; |
||||
&web-integration; |
||||
&portlet; |
||||
</part> |
||||
<part id="spring-integration"> |
||||
<title>Integration</title> |
||||
<partintro id="spring-integration-intro"> |
||||
<para> |
||||
This part of the reference documentation covers |
||||
the Spring Framework's integration with a number of J2EE |
||||
(and related) technologies. |
||||
</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para><xref linkend="remoting"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="ejb"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="jms"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="jmx"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="cci"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="mail"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="scheduling"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="dynamic-language"/></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><xref linkend="metadata"/></para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</partintro> |
||||
&remoting; |
||||
&ejb; |
||||
&jms; |
||||
&jmx; |
||||
&cci; |
||||
&mail; |
||||
&scheduling; |
||||
&dynamic-languages; |
||||
&metadata; |
||||
</part> |
||||
<!-- back matter --> |
||||
&xsd-configuration; |
||||
&xml-custom; |
||||
&dtd; |
||||
&spring-tld; |
||||
&spring-form-tld; |
||||
</book> |
||||
@ -0,0 +1,737 @@
@@ -0,0 +1,737 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<appendix id="spring.tld"> |
||||
<title>spring.tld</title> |
||||
<section id="spring.tld-intro"> |
||||
<title>Introduction</title> |
||||
</section> |
||||
<para>One of the view technologies you can use with the Spring Framework |
||||
is Java Server Pages (JSPs). To help you implement views using Java Server Pages |
||||
the Spring Framework provides you with some tags for evaluating errors, setting |
||||
themes and outputting internationalized messages.</para> |
||||
<para>Please note that the various tags generated by this form tag library |
||||
are compliant with the <ulink url="http://www.w3.org/TR/xhtml1/">XHTML-1.0-Strict specification</ulink> and attendant <ulink url="http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_XHTML-1.0-Strict">DTD</ulink>.</para> |
||||
<para>This appendix describes the <literal>spring.tld</literal> tag library.</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<xref linkend="spring.tld.bind"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="spring.tld.escapeBody"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="spring.tld.hasBindErrors"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="spring.tld.htmlEscape"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="spring.tld.message"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="spring.tld.nestedPath"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="spring.tld.theme"/> |
||||
</listitem> |
||||
<listitem> |
||||
<xref linkend="spring.tld.transform"/> |
||||
</listitem> |
||||
</itemizedlist> |
||||
<section id="spring.tld.bind"> |
||||
<title>The <literal>bind</literal> tag</title> |
||||
<para> |
||||
Provides BindStatus object for the given bind path. |
||||
The HTML escaping flag participates in a page-wide or application-wide setting |
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). |
||||
</para> |
||||
<table id="spring.tld.bind.table"> |
||||
<title>Attributes</title> |
||||
<tgroup cols="3"> |
||||
<colspec align="center" colname="Attribute"/> |
||||
<colspec align="center" colname="Required"/> |
||||
<colspec align="center" colname="Runtime.Expression"/> |
||||
<colspec align="left" colname="Description"/> |
||||
<thead> |
||||
<row> |
||||
<entry align="center">Attribute</entry> |
||||
<entry align="center">Required?</entry> |
||||
<entry align="center">Runtime Expression?</entry> |
||||
<entry align="left">Description</entry> |
||||
</row> |
||||
</thead> |
||||
<tbody> |
||||
<row> |
||||
<entry> |
||||
<para>htmlEscape</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set HTML escaping for this tag, as boolean value. Overrides |
||||
the default HTML escaping setting for the current page.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>ignoreNestedPath</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set whether to ignore a nested path, if any. Default is to not ignore.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>path</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The path to the bean or bean property to bind status |
||||
information for. For instance account.name, company.address.zipCode |
||||
or just employee. The status object will exported to the page scope, |
||||
specifically for this bean or bean property</para> |
||||
</entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
</section> |
||||
<section id="spring.tld.escapeBody"> |
||||
<title>The <literal>escapeBody</literal> tag</title> |
||||
<para> |
||||
Escapes its enclosed body content, applying HTML escaping and/or JavaScript escaping. |
||||
The HTML escaping flag participates in a page-wide or application-wide setting |
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). |
||||
</para> |
||||
<table id="spring.tld.escapeBody.table"> |
||||
<title>Attributes</title> |
||||
<tgroup cols="3"> |
||||
<colspec align="center" colname="Attribute"/> |
||||
<colspec align="center" colname="Required"/> |
||||
<colspec align="center" colname="Runtime.Expression"/> |
||||
<colspec align="left" colname="Description"/> |
||||
<thead> |
||||
<row> |
||||
<entry align="center">Attribute</entry> |
||||
<entry align="center">Required?</entry> |
||||
<entry align="center">Runtime Expression?</entry> |
||||
<entry align="left">Description</entry> |
||||
</row> |
||||
</thead> |
||||
<tbody> |
||||
<row> |
||||
<entry> |
||||
<para>htmlEscape</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set HTML escaping for this tag, as boolean value. Overrides the |
||||
default HTML escaping setting for the current page.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>javaScriptEscape</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set JavaScript escaping for this tag, as boolean value. |
||||
Default is false.</para> |
||||
</entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
</section> |
||||
<section id="spring.tld.hasBindErrors"> |
||||
<title>The <literal>hasBindErrors</literal> tag</title> |
||||
<para> |
||||
Provides Errors instance in case of bind errors. |
||||
The HTML escaping flag participates in a page-wide or application-wide setting |
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). |
||||
</para> |
||||
<table id="spring.tld.hasBindErrors.table"> |
||||
<title>Attributes</title> |
||||
<tgroup cols="3"> |
||||
<colspec align="center" colname="Attribute"/> |
||||
<colspec align="center" colname="Required"/> |
||||
<colspec align="center" colname="Runtime.Expression"/> |
||||
<colspec align="left" colname="Description"/> |
||||
<thead> |
||||
<row> |
||||
<entry align="center">Attribute</entry> |
||||
<entry align="center">Required?</entry> |
||||
<entry align="center">Runtime Expression?</entry> |
||||
<entry align="left">Description</entry> |
||||
</row> |
||||
</thead> |
||||
<tbody> |
||||
<row> |
||||
<entry> |
||||
<para>htmlEscape</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set HTML escaping for this tag, as boolean value. |
||||
Overrides the default HTML escaping setting for the current page.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>name</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The name of the bean in the request, that needs to be |
||||
inspected for errors. If errors are available for this bean, they |
||||
will be bound under the 'errors' key.</para> |
||||
</entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
</section> |
||||
<section id="spring.tld.htmlEscape"> |
||||
<title>The <literal>htmlEscape</literal> tag</title> |
||||
<para> |
||||
Sets default HTML escape value for the current page. |
||||
Overrides a "defaultHtmlEscape" context-param in web.xml, if any. |
||||
</para> |
||||
<table id="spring.tld.htmlEscape.table"> |
||||
<title>Attributes</title> |
||||
<tgroup cols="3"> |
||||
<colspec align="center" colname="Attribute"/> |
||||
<colspec align="center" colname="Required"/> |
||||
<colspec align="center" colname="Runtime.Expression"/> |
||||
<colspec align="left" colname="Description"/> |
||||
<thead> |
||||
<row> |
||||
<entry align="center">Attribute</entry> |
||||
<entry align="center">Required?</entry> |
||||
<entry align="center">Runtime Expression?</entry> |
||||
<entry align="left">Description</entry> |
||||
</row> |
||||
</thead> |
||||
<tbody> |
||||
<row> |
||||
<entry> |
||||
<para>defaultHtmlEscape</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set the default value for HTML escaping, to be put |
||||
into the current PageContext.</para> |
||||
</entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
</section> |
||||
<section id="spring.tld.message"> |
||||
<title>The <literal>message</literal> tag</title> |
||||
<para> |
||||
Retrieves the message with the given code, or text if code isn't resolvable. |
||||
The HTML escaping flag participates in a page-wide or application-wide setting |
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). |
||||
</para> |
||||
<table id="spring.tld.message.table"> |
||||
<title>Attributes</title> |
||||
<tgroup cols="3"> |
||||
<colspec align="center" colname="Attribute"/> |
||||
<colspec align="center" colname="Required"/> |
||||
<colspec align="center" colname="Runtime.Expression"/> |
||||
<colspec align="left" colname="Description"/> |
||||
<thead> |
||||
<row> |
||||
<entry align="center">Attribute</entry> |
||||
<entry align="center">Required?</entry> |
||||
<entry align="center">Runtime Expression?</entry> |
||||
<entry align="left">Description</entry> |
||||
</row> |
||||
</thead> |
||||
<tbody> |
||||
<row> |
||||
<entry> |
||||
<para>arguments</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set optional message arguments for this tag, as a |
||||
(comma-)delimited String (each String argument can contain JSP EL), |
||||
an Object array (used as argument array), or a single Object (used |
||||
as single argument).</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>argumentSeparator</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The separator character to be used for splitting the |
||||
arguments string value; defaults to a 'comma' (',').</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>code</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The code (key) to use when looking up the message. |
||||
If code is not provided, the text attribute will be used.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>htmlEscape</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set HTML escaping for this tag, as boolean value. |
||||
Overrides the default HTML escaping setting for the current page.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>javaScriptEscape</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set JavaScript escaping for this tag, as boolean value. Default is false.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>message</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>A MessageSourceResolvable argument (direct or through JSP EL). |
||||
Fits nicely when used in conjunction with Spring's own validation error |
||||
classes which all implement the MessageSourceResolvable interface. For |
||||
example, this allows you to iterate over all of the errors in a form, |
||||
passing each error (using a runtime expression) as the value of this |
||||
'message' attribute, thus effecting the easy display of such error |
||||
messages.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>scope</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The scope to use when exporting the result to a variable. |
||||
This attribute is only used when var is also set. Possible values are |
||||
page, request, session and application.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>text</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Default text to output when a message for the given code |
||||
could not be found. If both text and code are not set, the tag will |
||||
output null.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>var</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The string to use when binding the result to the page, |
||||
request, session or application scope. If not specified, the result |
||||
gets outputted to the writer (i.e. typically directly to the JSP).</para> |
||||
</entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
</section> |
||||
<section id="spring.tld.nestedPath"> |
||||
<title>The <literal>nestedPath</literal> tag</title> |
||||
<para> |
||||
Sets a nested path to be used by the bind tag's path. |
||||
</para> |
||||
<table id="spring.tld.nestedPath.table"> |
||||
<title>Attributes</title> |
||||
<tgroup cols="3"> |
||||
<colspec align="center" colname="Attribute"/> |
||||
<colspec align="center" colname="Required"/> |
||||
<colspec align="center" colname="Runtime.Expression"/> |
||||
<colspec align="left" colname="Description"/> |
||||
<thead> |
||||
<row> |
||||
<entry align="center">Attribute</entry> |
||||
<entry align="center">Required?</entry> |
||||
<entry align="center">Runtime Expression?</entry> |
||||
<entry align="left">Description</entry> |
||||
</row> |
||||
</thead> |
||||
<tbody> |
||||
<row> |
||||
<entry> |
||||
<para>path</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set the path that this tag should apply. E.g. 'customer' |
||||
to allow bind paths like 'address.street' rather than |
||||
'customer.address.street'.</para> |
||||
</entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
</section> |
||||
<section id="spring.tld.theme"> |
||||
<title>The <literal>theme</literal> tag</title> |
||||
<para> |
||||
Retrieves the theme message with the given code, or text if code isn't resolvable. |
||||
The HTML escaping flag participates in a page-wide or application-wide setting |
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml). |
||||
</para> |
||||
<table id="spring.tld.theme.table"> |
||||
<title>Attributes</title> |
||||
<tgroup cols="3"> |
||||
<colspec align="center" colname="Attribute"/> |
||||
<colspec align="center" colname="Required"/> |
||||
<colspec align="center" colname="Runtime.Expression"/> |
||||
<colspec align="left" colname="Description"/> |
||||
<thead> |
||||
<row> |
||||
<entry align="center">Attribute</entry> |
||||
<entry align="center">Required?</entry> |
||||
<entry align="center">Runtime Expression?</entry> |
||||
<entry align="left">Description</entry> |
||||
</row> |
||||
</thead> |
||||
<tbody> |
||||
<row> |
||||
<entry> |
||||
<para>arguments</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set optional message arguments for this tag, as a |
||||
(comma-)delimited String (each String argument can contain JSP EL), |
||||
an Object array (used as argument array), or a single Object (used |
||||
as single argument).</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>argumentSeparator</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The separator character to be used for splitting the |
||||
arguments string value; defaults to a 'comma' (',').</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>code</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The code (key) to use when looking up the message. |
||||
If code is not provided, the text attribute will be used.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>htmlEscape</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set HTML escaping for this tag, as boolean value. |
||||
Overrides the default HTML escaping setting for the current page.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>javaScriptEscape</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set JavaScript escaping for this tag, as boolean value. Default is false.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>message</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>A MessageSourceResolvable argument (direct or through JSP EL).</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>scope</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The scope to use when exporting the result to a variable. |
||||
This attribute is only used when var is also set. Possible values are |
||||
page, request, session and application.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>text</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Default text to output when a message for the given code |
||||
could not be found. If both text and code are not set, the tag will |
||||
output null.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>var</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The string to use when binding the result to the page, |
||||
request, session or application scope. If not specified, the result |
||||
gets outputted to the writer (i.e. typically directly to the JSP).</para> |
||||
</entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
</section> |
||||
<section id="spring.tld.transform"> |
||||
<title>The <literal>transform</literal> tag</title> |
||||
<para> |
||||
Provides transformation of variables to Strings, using an appropriate |
||||
custom PropertyEditor from BindTag (can only be used inside BindTag). |
||||
The HTML escaping flag participates in a page-wide or application-wide setting |
||||
(i.e. by HtmlEscapeTag or a 'defaultHtmlEscape' context-param in web.xml). |
||||
</para> |
||||
<table id="spring.tld.transform.table"> |
||||
<title>Attributes</title> |
||||
<tgroup cols="3"> |
||||
<colspec align="center" colname="Attribute"/> |
||||
<colspec align="center" colname="Required"/> |
||||
<colspec align="center" colname="Runtime.Expression"/> |
||||
<colspec align="left" colname="Description"/> |
||||
<thead> |
||||
<row> |
||||
<entry align="center">Attribute</entry> |
||||
<entry align="center">Required?</entry> |
||||
<entry align="center">Runtime Expression?</entry> |
||||
<entry align="left">Description</entry> |
||||
</row> |
||||
</thead> |
||||
<tbody> |
||||
<row> |
||||
<entry> |
||||
<para>htmlEscape</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>Set HTML escaping for this tag, as boolean value. Overrides |
||||
the default HTML escaping setting for the current page.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>scope</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The scope to use when exported the result to a variable. |
||||
This attribute is only used when var is also set. Possible values are |
||||
page, request, session and application.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>value</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The value to transform. This is the actual object you want |
||||
to have transformed (for instance a Date). Using the PropertyEditor that |
||||
is currently in use by the 'spring:bind' tag.</para> |
||||
</entry> |
||||
</row> |
||||
<row> |
||||
<entry> |
||||
<para>var</para> |
||||
</entry> |
||||
<entry> |
||||
<para>false</para> |
||||
</entry> |
||||
<entry> |
||||
<para>true</para> |
||||
</entry> |
||||
<entry> |
||||
<para>The string to use when binding the result to the page, |
||||
request, session or application scope. If not specified, the result gets |
||||
outputted to the writer (i.e. typically directly to the JSP).</para> |
||||
</entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
</section> |
||||
</appendix> |
||||
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<sidebar> |
||||
<title>Spring Web Flow</title> |
||||
|
||||
<para>Spring Web Flow (SWF) aims to be the best solution for the management |
||||
of web application page flow.</para> |
||||
|
||||
<para>SWF integrates with existing frameworks like Spring MVC, Struts, and |
||||
JSF, in both servlet and portlet environments. If you have a business |
||||
process (or processes) that would benefit from a conversational model as |
||||
opposed to a purely request model, then SWF may be the solution.</para> |
||||
|
||||
<para>SWF allows you to capture logical page flows as self-contained modules |
||||
that are reusable in different situations, and as such is ideal for building |
||||
web application modules that guide the user through controlled navigations |
||||
that drive business processes.</para> |
||||
|
||||
<para>For more information about SWF, consult the |
||||
<ulink url="http://www.springframework.org/webflow">Spring Web Flow website</ulink>. |
||||
</para> |
||||
</sidebar> |
||||
@ -0,0 +1,749 @@
@@ -0,0 +1,749 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<chapter id="validation"> |
||||
<title>Validation, Data-binding, the <interfacename>BeanWrapper</interfacename>, and <literal>PropertyEditors</literal></title> |
||||
|
||||
<section id="validation-introduction"> |
||||
<title>Introduction</title> |
||||
|
||||
<para>There are pros and cons for considering validation as business logic, |
||||
and Spring offers a design for validation (and data binding) that |
||||
does not exclude either one of them. Specifically validation should not be |
||||
tied to the web tier, should be easy to localize and it should be |
||||
possible to plug in any validator available. Considering the above, Spring |
||||
has come up with a <interfacename>Validator</interfacename> interface that |
||||
is both basic and eminently usable in every layer of an application.</para> |
||||
|
||||
<para>Data binding is useful for allowing user input to be dynamically |
||||
bound to the domain model of an application (or whatever objects you use |
||||
to process user input). Spring provides the so-called |
||||
<interfacename>DataBinder</interfacename> to do exactly that. The |
||||
<interfacename>Validator</interfacename> and the |
||||
<interfacename>DataBinder</interfacename> make up the <literal>validation</literal> package, |
||||
which is primarily used in but not limited to the MVC framework.</para> |
||||
|
||||
<para>The <interfacename>BeanWrapper</interfacename> is a fundamental concept in the |
||||
Spring Framework and is used in a lot of places. However, you probably |
||||
will not ever have the need to use the <interfacename>BeanWrapper</interfacename> directly. Because this |
||||
is reference documentation however, we felt that some explanation might be |
||||
in order. We're explaining the <interfacename>BeanWrapper</interfacename> in this chapter since if you were |
||||
going to use it at all, you would probably do so when trying to bind |
||||
data to objects, which is strongly related to the <interfacename>BeanWrapper</interfacename>.</para> |
||||
|
||||
<para>Spring uses PropertyEditors all over the place. The concept of a |
||||
<interfacename>PropertyEditor</interfacename> is part of the JavaBeans specification. Just as the |
||||
<interfacename>BeanWrapper</interfacename>, it's best to explain the use of PropertyEditors in this |
||||
chapter as well, since it's closely related to the <interfacename>BeanWrapper</interfacename> and the |
||||
<interfacename>DataBinder</interfacename>.</para> |
||||
</section> |
||||
|
||||
<section id="validator"> |
||||
<title>Validation using Spring's <interfacename>Validator</interfacename> interface</title> |
||||
<para>Spring's features a <interfacename>Validator</interfacename> interface that you can |
||||
use to validate objects. The <interfacename>Validator</interfacename> interface works using |
||||
an <interfacename>Errors</interfacename> object so that while validating, validators can report |
||||
validation failures to the <interfacename>Errors</interfacename> object.</para> |
||||
<para>Let's consider a small data object:</para> |
||||
<programlisting><![CDATA[ |
||||
public class Person { |
||||
|
||||
private String name; |
||||
private int age; |
||||
|
||||
]]><lineannotation>// the usual getters and setters...</lineannotation><![CDATA[ |
||||
}]]></programlisting> |
||||
<para>We're going to provide validation behavior for the <classname>Person</classname> |
||||
class by implementing the following two methods of the |
||||
<interfacename>org.springframework.validation.Validator</interfacename> interface: |
||||
<itemizedlist spacing="compact"> |
||||
<listitem> |
||||
<para><methodname>supports(Class)</methodname> - Can this |
||||
<interfacename>Validator</interfacename> validate instances of the supplied |
||||
<classname>Class</classname>?</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><methodname>validate(Object, org.springframework.validation.Errors)</methodname> - |
||||
validates the given object and in case of validation errors, registers |
||||
those with the given <interfacename>Errors</interfacename> object</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</para> |
||||
<para> |
||||
Implementing a <interfacename>Validator</interfacename> is fairly straightforward, |
||||
especially when you know of the <classname>ValidationUtils</classname> helper class |
||||
that the Spring Framework also provides.</para> |
||||
<programlisting><![CDATA[public class PersonValidator implements Validator { |
||||
|
||||
]]><lineannotation>/** |
||||
* This <interfacename>Validator</interfacename> validates <emphasis role="bold">just</emphasis> <classname>Person</classname> instances |
||||
*/</lineannotation><![CDATA[ |
||||
public boolean supports(Class clazz) { |
||||
return Person.class.equals(clazz); |
||||
} |
||||
|
||||
public void validate(Object obj, Errors e) { |
||||
ValidationUtils.rejectIfEmpty(e, "name", "name.empty"); |
||||
Person p = (Person) obj; |
||||
if (p.getAge() < 0) { |
||||
e.rejectValue("age", "negativevalue"); |
||||
} else if (p.getAge() > 110) { |
||||
e.rejectValue("age", "too.darn.old"); |
||||
} |
||||
} |
||||
}]]></programlisting> |
||||
<para>As you can see, the <literal>static</literal> <methodname>rejectIfEmpty(..)</methodname> |
||||
method on the <classname>ValidationUtils</classname> class is used to reject the |
||||
<literal>'name'</literal> property if it is <literal>null</literal> or the empty string. |
||||
Have a look at the Javadoc for the <classname>ValidationUtils</classname> class to see |
||||
what functionality it provides besides the example shown previously.</para> |
||||
<para>While it is certainly possible to implement a single |
||||
<interfacename>Validator</interfacename> class to validate each of the nested objects |
||||
in a rich object, it may be better to encapsulate the validation logic for each nested |
||||
class of object in its own <interfacename>Validator</interfacename> implementation. A |
||||
simple example of a <emphasis>'rich'</emphasis> object would be a |
||||
<classname>Customer</classname> that is composed of two <classname>String</classname> |
||||
properties (a first and second name) and a complex <classname>Address</classname> object. |
||||
<classname>Address</classname> objects may be used independently of |
||||
<classname>Customer</classname> objects, and so a distinct |
||||
<classname>AddressValidator</classname> has been implemented. If you want your |
||||
<classname>CustomerValidator</classname> to reuse the logic contained within the |
||||
<classname>AddressValidator</classname> class without recourse to copy-n-paste you can |
||||
dependency-inject or instantiate an <classname>AddressValidator</classname> within your |
||||
<classname>CustomerValidator</classname>, and use it like so:</para> |
||||
<programlisting><![CDATA[public class CustomerValidator implements Validator { |
||||
|
||||
private final Validator addressValidator; |
||||
|
||||
public CustomerValidator(Validator addressValidator) { |
||||
if (addressValidator == null) { |
||||
throw new IllegalArgumentException("The supplied [Validator] is required and must not be null."); |
||||
} |
||||
if (!addressValidator.supports(Address.class)) { |
||||
throw new IllegalArgumentException( |
||||
"The supplied [Validator] must support the validation of [Address] instances."); |
||||
} |
||||
this.addressValidator = addressValidator; |
||||
} |
||||
|
||||
]]><lineannotation>/** |
||||
* This <interfacename>Validator</interfacename> validates <classname>Customer</classname> instances, and any subclasses of <classname>Customer</classname> too |
||||
*/</lineannotation><![CDATA[ |
||||
public boolean supports(Class clazz) { |
||||
return Customer.class.isAssignableFrom(clazz); |
||||
} |
||||
|
||||
public void validate(Object target, Errors errors) { |
||||
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required"); |
||||
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required"); |
||||
Customer customer = (Customer) target; |
||||
try { |
||||
errors.pushNestedPath("address"); |
||||
ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors); |
||||
} finally { |
||||
errors.popNestedPath(); |
||||
} |
||||
} |
||||
}]]></programlisting> |
||||
<para>Validation errors are reported to the <interfacename>Errors</interfacename> |
||||
object passed to the validator. In case of Spring Web MVC you can use |
||||
<literal><spring:bind/></literal> tag to inspect the error messages, but |
||||
of course you can also inspect the errors object yourself. More information about |
||||
the methods it offers can be found from the Javadoc.</para> |
||||
</section> |
||||
<section id="validation-conversion"> |
||||
<title>Resolving codes to error messages</title> |
||||
<para>We've talked about databinding and validation. Outputting messages corresponding to |
||||
validation errors is the last thing we need to discuss. In the example we've shown |
||||
above, we rejected the <literal>name</literal> and the <literal>age</literal> field. |
||||
If we're going to output the error messages by using a <interfacename>MessageSource</interfacename>, |
||||
we will do so using the error code we've given when rejecting the field ('name' and 'age' |
||||
in this case). When you call (either directly, or indirectly, using for example the |
||||
<classname>ValidationUtils</classname> class) <literal>rejectValue</literal> or one of |
||||
the other <literal>reject</literal> methods from the <interfacename>Errors</interfacename> |
||||
interface, the underlying implementation will not only register the code you've |
||||
passed in, but also a number of additional error codes. What error codes it registers |
||||
is determined by the <interfacename>MessageCodesResolver</interfacename> that is used. |
||||
By default, the <classname>DefaultMessageCodesResolver</classname> is used, which for example |
||||
not only registers a message with the code you gave, but also messages that include the |
||||
field name you passed to the reject method. So in case you reject a field using |
||||
<literal>rejectValue("age", "too.darn.old")</literal>, apart from the |
||||
<literal>too.darn.old</literal> code, Spring will also register |
||||
<literal>too.darn.old.age</literal> and <literal>too.darn.old.age.int</literal> |
||||
(so the first will include the field name and the second will include the type of the |
||||
field); this is done as a convenience to aid developers in targeting error |
||||
messages and suchlike.</para> |
||||
<para>More information on the <interfacename>MessageCodesResolver</interfacename> and the default |
||||
strategy can be found online with the Javadocs for |
||||
<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/validation/MessageCodesResolver.html">MessageCodesResolver</ulink> |
||||
and |
||||
<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/validation/DefaultMessageCodesResolver.html">DefaultMessageCodesResolver</ulink> |
||||
respectively.</para> |
||||
</section> |
||||
|
||||
<section id="beans-beans"> |
||||
<title>Bean manipulation and the <interfacename>BeanWrapper</interfacename></title> |
||||
|
||||
<para>The <literal>org.springframework.beans</literal> package adheres to |
||||
the JavaBeans standard provided by Sun. A JavaBean is simply a class with |
||||
a default no-argument constructor, which follows a naming convention |
||||
where (by way of an example) a property named <literal>bingoMadness</literal> would have a setter |
||||
method <methodname>setBingoMadness(..)</methodname> and a getter method <methodname>getBingoMadness()</methodname>. |
||||
For more information about JavaBeans and the specification, please refer |
||||
to Sun's website ( <ulink url="http://java.sun.com/products/javabeans/">java.sun.com/products/javabeans</ulink>).</para> |
||||
|
||||
<para>One quite important class in the beans package is the |
||||
<interfacename>BeanWrapper</interfacename> interface and its corresponding |
||||
implementation (<classname>BeanWrapperImpl</classname>). As quoted from the |
||||
Javadoc, the <interfacename>BeanWrapper</interfacename> offers functionality to set and get property |
||||
values (individually or in bulk), get property descriptors, and to query |
||||
properties to determine if they are readable or writable. Also, the |
||||
<interfacename>BeanWrapper</interfacename> offers support for nested properties, enabling the setting of |
||||
properties on sub-properties to an unlimited depth. Then, the <interfacename>BeanWrapper</interfacename> |
||||
supports the ability to add standard JavaBeans |
||||
<interfacename>PropertyChangeListeners</interfacename> and |
||||
<interfacename>VetoableChangeListeners</interfacename>, without the need for |
||||
supporting code in the target class. Last but not least, the <interfacename>BeanWrapper</interfacename> |
||||
provides support for the setting of indexed properties. The <interfacename>BeanWrapper</interfacename> |
||||
usually isn't used by application code directly, but by the |
||||
<interfacename>DataBinder</interfacename> and the |
||||
<interfacename>BeanFactory</interfacename>.</para> |
||||
|
||||
<para>The way the <interfacename>BeanWrapper</interfacename> works is partly indicated by its name: |
||||
<emphasis>it wraps a bean</emphasis> to perform actions on that bean, like |
||||
setting and retrieving properties.</para> |
||||
|
||||
<section id="beans-beans-conventions"> |
||||
<title>Setting and getting basic and nested properties</title> |
||||
|
||||
<para>Setting and getting properties is done using the |
||||
<literal>setPropertyValue(s)</literal> and |
||||
<literal>getPropertyValue(s)</literal> methods that both come with a |
||||
couple of overloaded variants. They're all described in more detail in |
||||
the Javadoc Spring comes with. What's important to know is that there |
||||
are a couple of conventions for indicating properties of an object. A |
||||
couple of examples:</para> |
||||
<table id="beans-beans-conventions-properties-tbl"> |
||||
<title>Examples of properties</title> |
||||
|
||||
<tgroup cols="2"> |
||||
<colspec colname="c1" colwidth="1*" /> |
||||
<colspec colname="c2" colwidth="3*" /> |
||||
<thead> |
||||
<row> |
||||
<entry>Expression</entry> |
||||
<entry>Explanation</entry> |
||||
</row> |
||||
</thead> |
||||
|
||||
<tbody> |
||||
<row> |
||||
<entry><literal>name</literal></entry> |
||||
|
||||
<entry>Indicates the property <literal>name</literal> |
||||
corresponding to the methods <methodname>getName()</methodname> or |
||||
<methodname>isName()</methodname> and |
||||
<methodname>setName(..)</methodname></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>account.name</literal></entry> |
||||
|
||||
<entry>Indicates the nested property <literal>name</literal> |
||||
of the property <literal>account</literal> corresponding e.g. |
||||
to the methods <literal>getAccount().setName()</literal> or |
||||
<literal>getAccount().getName()</literal></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>account[2]</literal></entry> |
||||
|
||||
<entry>Indicates the <emphasis>third</emphasis> element of the |
||||
indexed property <literal>account</literal>. Indexed |
||||
properties can be of type <literal>array</literal>, |
||||
<literal>list</literal> or other <emphasis>naturally |
||||
ordered</emphasis> collection</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>account[COMPANYNAME]</literal></entry> |
||||
|
||||
<entry>Indicates the value of the map entry indexed by the key |
||||
<emphasis>COMPANYNAME</emphasis> of the Map property |
||||
<literal>account</literal></entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
|
||||
<para>Below you'll find some examples of working with the <interfacename>BeanWrapper</interfacename> to |
||||
get and set properties.</para> |
||||
|
||||
<para><emphasis>(This next section is not vitally important to you if you're not |
||||
planning to work with the <interfacename>BeanWrapper</interfacename> directly. If you're |
||||
just using the <interfacename>DataBinder</interfacename> and the |
||||
<interfacename>BeanFactory</interfacename> and their out-of-the-box implementation, you |
||||
should skip ahead to the section about |
||||
<interfacename>PropertyEditors</interfacename>.)</emphasis></para> |
||||
|
||||
<para>Consider the following two classes:</para> |
||||
<programlisting><![CDATA[public class Company { |
||||
private String name; |
||||
private Employee managingDirector; |
||||
|
||||
public String getName() { |
||||
return this.name; |
||||
} |
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
public Employee getManagingDirector() { |
||||
return this.managingDirector; |
||||
} |
||||
public void setManagingDirector(Employee managingDirector) { |
||||
this.managingDirector = managingDirector; |
||||
} |
||||
}]]></programlisting> |
||||
|
||||
<programlisting><![CDATA[public class Employee { |
||||
private String name; |
||||
private float salary; |
||||
|
||||
public String getName() { |
||||
return this.name; |
||||
} |
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
public float getSalary() { |
||||
return salary; |
||||
} |
||||
public void setSalary(float salary) { |
||||
this.salary = salary; |
||||
} |
||||
}]]></programlisting> |
||||
|
||||
<para>The following code snippets show some examples of how to retrieve |
||||
and manipulate some of the properties of instantiated |
||||
<literal>Companies</literal> and <literal>Employees</literal>:</para> |
||||
<programlisting><![CDATA[BeanWrapper company = BeanWrapperImpl(new Company()); |
||||
]]><lineannotation>// setting the company name..</lineannotation><![CDATA[ |
||||
company.setPropertyValue("name", "Some Company Inc."); |
||||
]]><lineannotation>// ... can also be done like this:</lineannotation><![CDATA[ |
||||
PropertyValue value = new PropertyValue("name", "Some Company Inc."); |
||||
company.setPropertyValue(value); |
||||
|
||||
]]><lineannotation>// ok, let's create the director and tie it to the company:</lineannotation><![CDATA[ |
||||
BeanWrapper jim = BeanWrapperImpl(new Employee()); |
||||
jim.setPropertyValue("name", "Jim Stravinsky"); |
||||
company.setPropertyValue("managingDirector", jim.getWrappedInstance()); |
||||
|
||||
]]><lineannotation>// retrieving the salary of the managingDirector through the company</lineannotation><![CDATA[ |
||||
Float salary = (Float) company.getPropertyValue("managingDirector.salary");]]></programlisting> |
||||
</section> |
||||
|
||||
<section id="beans-beans-conversion"> |
||||
<title>Built-in <interface>PropertyEditor</interface> implementations</title> |
||||
|
||||
<para>Spring heavily uses the concept of <literal>PropertyEditors</literal> to effect the conversion |
||||
between an <classname>Object</classname> and a <classname>String</classname>. If you think about it, |
||||
it sometimes might be handy to be able to represent properties in a different way than the object itself. |
||||
For example, a <classname>Date</classname> can be represented in a human readable way (as the |
||||
<classname>String</classname> '<literal>2007-14-09</literal>'), while we're still able to convert the |
||||
human readable form back to the original date (or even better: convert any date entered in a human readable |
||||
form, back to <classname>Date</classname> objects). This behavior can be achieved by |
||||
<emphasis>registering custom editors</emphasis>, of type <interfacename>java.beans.PropertyEditor</interfacename>. |
||||
Registering custom editors on a <interfacename>BeanWrapper</interfacename> or alternately in a specific IoC |
||||
container as mentioned in the previous chapter, gives it the knowledge of how to convert properties to the |
||||
desired type. Read more about <interfacename>PropertyEditors</interfacename> in the Javadoc of the |
||||
<literal>java.beans</literal> package provided by Sun.</para> |
||||
|
||||
<para>A couple of examples where property editing is used in Spring: |
||||
<itemizedlist spacing="compact"> |
||||
<listitem> |
||||
<para><emphasis>setting properties on beans</emphasis> is done |
||||
using <literal>PropertyEditors</literal>. When mentioning |
||||
<literal>java.lang.String</literal> as the value of a property of |
||||
some bean you're declaring in XML file, Spring will (if the setter |
||||
of the corresponding property has a <classname>Class</classname>-parameter) use the |
||||
<classname>ClassEditor</classname> to try to resolve the parameter to |
||||
a <classname>Class</classname> object.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><emphasis>parsing HTTP request parameters</emphasis> in |
||||
Spring's MVC framework is done using all kinds of <literal>PropertyEditors</literal> |
||||
that you can manually bind in all subclasses of the |
||||
<classname>CommandController</classname>.</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</para> |
||||
|
||||
<para>Spring has a number of built-in <literal>PropertyEditors</literal> to make life easy. |
||||
Each of those is listed below and they are all located in the |
||||
<literal>org.springframework.beans.propertyeditors</literal> package. Most, but not all (as indicated below), |
||||
are registered by default by <classname>BeanWrapperImpl</classname>. Where the property editor is configurable |
||||
in some fashion, you can of course still register your own variant to override the default one:</para> |
||||
|
||||
<table id="beans-beans-property-editors-tbl"> |
||||
<title>Built-in <literal>PropertyEditors</literal></title> |
||||
|
||||
<tgroup cols="2"> |
||||
<colspec colname="c1" colwidth="3*" /> |
||||
<colspec colname="c2" colwidth="5*" /> |
||||
|
||||
<thead> |
||||
<row> |
||||
<entry>Class</entry> |
||||
<entry>Explanation</entry> |
||||
</row> |
||||
</thead> |
||||
|
||||
<tbody> |
||||
<row> |
||||
<entry><classname>ByteArrayPropertyEditor</classname></entry> |
||||
|
||||
<entry>Editor for byte arrays. Strings will simply be |
||||
converted to their corresponding byte representations. |
||||
Registered by default by <classname>BeanWrapperImpl</classname>.</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><classname>ClassEditor</classname></entry> |
||||
|
||||
<entry>Parses Strings representing classes to actual classes |
||||
and the other way around. When a class is not found, an |
||||
<classname>IllegalArgumentException</classname> is thrown. Registered by default by |
||||
<classname>BeanWrapperImpl</classname>.</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><classname>CustomBooleanEditor</classname></entry> |
||||
|
||||
<entry>Customizable property editor for <classname>Boolean</classname> properties. |
||||
Registered by default by <classname>BeanWrapperImpl</classname>, but, can be |
||||
overridden by registering custom instance of it as custom |
||||
editor.</entry> |
||||
</row> |
||||
<row> |
||||
<entry><classname>CustomCollectionEditor</classname></entry> |
||||
<entry>Property editor for Collections, converting any source |
||||
<interfacename>Collection</interfacename> to a given target <interfacename>Collection</interfacename> type.</entry> |
||||
</row> |
||||
<row> |
||||
<entry><classname>CustomDateEditor</classname></entry> |
||||
|
||||
<entry>Customizable property editor for java.util.Date, |
||||
supporting a custom DateFormat. NOT registered by default. Must |
||||
be user registered as needed with appropriate format.</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><classname>CustomNumberEditor</classname></entry> |
||||
|
||||
<entry>Customizable property editor for any Number subclass |
||||
like <classname>Integer</classname>, <classname>Long</classname>, |
||||
<classname>Float</classname>, <classname>Double</classname>. Registered |
||||
by default by <classname>BeanWrapperImpl</classname>, but can be |
||||
overridden by registering custom instance of it as a custom editor.</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><classname>FileEditor</classname></entry> |
||||
|
||||
<entry>Capable of resolving Strings to |
||||
<classname>java.io.File</classname> objects. Registered by default by |
||||
<classname>BeanWrapperImpl</classname>. </entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><classname>InputStreamEditor</classname></entry> |
||||
|
||||
<entry>One-way property editor, capable of taking a text |
||||
string and producing (via an intermediate <classname>ResourceEditor</classname> and |
||||
<interfacename>Resource</interfacename>) an |
||||
<interfacename>InputStream</interfacename>, so <interfacename>InputStream</interfacename> |
||||
properties may be directly set as Strings. Note that the default usage |
||||
will not close the <interfacename>InputStream</interfacename> for |
||||
you! Registered by default by <classname>BeanWrapperImpl</classname>.</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><classname>LocaleEditor</classname></entry> |
||||
|
||||
<entry>Capable of resolving Strings to |
||||
<classname>Locale</classname> objects and vice versa (the String |
||||
format is [language]_[country]_[variant], which is the same |
||||
thing the toString() method of Locale provides). Registered by |
||||
default by <classname>BeanWrapperImpl</classname>.</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><classname>PatternEditor</classname></entry> |
||||
|
||||
<entry>Capable of resolving Strings to JDK 1.5 |
||||
<classname>Pattern</classname> objects and vice versa.</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><classname>PropertiesEditor</classname></entry> |
||||
|
||||
<entry>Capable of converting Strings (formatted using the |
||||
format as defined in the Javadoc for the java.lang.Properties |
||||
class) to <classname>Properties</classname> objects. Registered by |
||||
default by <classname>BeanWrapperImpl</classname>.</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><classname>StringTrimmerEditor</classname></entry> |
||||
|
||||
<entry>Property editor that trims Strings. Optionally allows |
||||
transforming an empty string into a <literal>null</literal> value. NOT |
||||
registered by default; must be user registered as needed.</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><classname>URLEditor</classname></entry> |
||||
|
||||
<entry>Capable of resolving a String representation of a URL |
||||
to an actual <classname>URL</classname> object. Registered by |
||||
default by <classname>BeanWrapperImpl</classname>.</entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table> |
||||
|
||||
<para> |
||||
Spring uses the <interfacename>java.beans.PropertyEditorManager</interfacename> to set |
||||
the search path for property editors that might be needed. The search path also includes |
||||
<literal>sun.bean.editors</literal>, which includes |
||||
<interfacename>PropertyEditor</interfacename> implementations for types such as |
||||
<classname>Font</classname>, <classname>Color</classname>, and most of the primitive types. |
||||
Note also that the standard JavaBeans infrastructure will automatically discover |
||||
<interfacename>PropertyEditor</interfacename> classes (without you having to register them |
||||
explicitly) if they are in the same package as the class they handle, and have the same name |
||||
as that class, with <literal>'Editor'</literal> appended; for example, one could have the |
||||
following class and package structure, which would be sufficient for the |
||||
<classname>FooEditor</classname> class to be recognized and used as the |
||||
<interfacename>PropertyEditor</interfacename> for <classname>Foo</classname>-typed |
||||
properties. |
||||
</para> |
||||
<programlisting><![CDATA[com |
||||
chank |
||||
pop |
||||
Foo |
||||
FooEditor ]]><lineannotation>// the <interfacename>PropertyEditor</interfacename> for the <classname>Foo</classname> class</lineannotation></programlisting> |
||||
<para>Note that you can also use the standard <interfacename>BeanInfo</interfacename> JavaBeans |
||||
mechanism here as well (described |
||||
<ulink url="http://java.sun.com/docs/books/tutorial/javabeans/customization/index.html">in not-amazing-detail here</ulink>). |
||||
Find below an example of using the <interfacename>BeanInfo</interfacename> mechanism for |
||||
explicitly registering one or more <interfacename>PropertyEditor</interfacename> instances |
||||
with the properties of an associated class.</para> |
||||
<programlisting><![CDATA[com |
||||
chank |
||||
pop |
||||
Foo |
||||
FooBeanInfo ]]><lineannotation>// the <interfacename>BeanInfo</interfacename> for the <classname>Foo</classname> class</lineannotation></programlisting> |
||||
<para> |
||||
Here is the Java source code for the referenced <classname>FooBeanInfo</classname> class. This |
||||
would associate a <classname>CustomNumberEditor</classname> with the <literal>age</literal> |
||||
property of the <classname>Foo</classname> class. |
||||
</para> |
||||
<programlisting><![CDATA[public class FooBeanInfo extends SimpleBeanInfo { |
||||
|
||||
public PropertyDescriptor[] getPropertyDescriptors() { |
||||
try { |
||||
final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true); |
||||
PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) { |
||||
public PropertyEditor createPropertyEditor(Object bean) { |
||||
return numberPE; |
||||
}; |
||||
}; |
||||
return new PropertyDescriptor[] { ageDescriptor }; |
||||
} |
||||
catch (IntrospectionException ex) { |
||||
throw new Error(ex.toString()); |
||||
} |
||||
} |
||||
}]]></programlisting> |
||||
|
||||
|
||||
<section id="beans-beans-conversion-customeditor-registration"> |
||||
<title>Registering additional custom <interfacename>PropertyEditors</interfacename></title> |
||||
|
||||
<para>When setting bean properties as a string value, a Spring IoC container |
||||
ultimately uses standard JavaBeans <literal>PropertyEditors</literal> to convert these |
||||
Strings to the complex type of the property. Spring pre-registers a number |
||||
of custom <literal>PropertyEditors</literal> (for example, to convert a classname expressed |
||||
as a string into a real <classname>Class</classname> object). Additionally, Java's standard |
||||
JavaBeans <interfacename>PropertyEditor</interfacename> lookup mechanism allows a |
||||
<classname>PropertyEditor</classname> for a class simply to be named appropriately and |
||||
placed in the same package as the class it provides support for, to be found automatically.</para> |
||||
<para>If there is a need to register other custom <literal>PropertyEditors</literal>, there |
||||
are several mechanisms available. The most manual approach, which is not normally convenient or |
||||
recommended, is to simply use the <methodname>registerCustomEditor()</methodname> method of the |
||||
<interfacename>ConfigurableBeanFactory</interfacename> interface, assuming you have a |
||||
<interfacename>BeanFactory</interfacename> reference. Another, slightly more convenient, mechanism is to use |
||||
a special bean factory post-processor called <classname>CustomEditorConfigurer</classname>. |
||||
Although bean factory post-processors can be used with <interfacename>BeanFactory</interfacename> |
||||
implementations, the <classname>CustomEditorConfigurer</classname> has a nested property setup, so it is |
||||
strongly recommended that it is used with the <interfacename>ApplicationContext</interfacename>, where |
||||
it may be deployed in similar fashion to any other bean, and automatically detected and applied.</para> |
||||
<para>Note that all bean factories and application contexts automatically use a number of built-in property |
||||
editors, through their use of something called a <interfacename>BeanWrapper</interfacename> to handle |
||||
property conversions. The standard property editors that the <interfacename>BeanWrapper</interfacename> |
||||
registers are listed in <link linkend="beans-beans-conversion">the previous section</link>. Additionally, |
||||
<literal>ApplicationContexts</literal> also override or add an additional number of editors |
||||
to handle resource lookups in a manner appropriate to the specific application context type.</para> |
||||
|
||||
<para>Standard JavaBeans <interfacename>PropertyEditor</interfacename> instances are used to convert |
||||
property values expressed as strings to the actual complex type of the property. |
||||
<classname>CustomEditorConfigurer</classname>, a bean factory post-processor, may be used to conveniently |
||||
add support for additional <interfacename>PropertyEditor</interfacename> instances to an |
||||
<interfacename>ApplicationContext</interfacename>.</para> |
||||
<para>Consider a user class <classname>ExoticType</classname>, and another class |
||||
<classname>DependsOnExoticType</classname> which needs <classname>ExoticType</classname> set as a property:</para> |
||||
|
||||
<programlisting><![CDATA[package example; |
||||
|
||||
public class ExoticType { |
||||
|
||||
private String name; |
||||
|
||||
public ExoticType(String name) { |
||||
this.name = name; |
||||
} |
||||
} |
||||
|
||||
public class DependsOnExoticType { |
||||
|
||||
private ExoticType type; |
||||
|
||||
public void setType(ExoticType type) { |
||||
this.type = type; |
||||
} |
||||
}]]></programlisting> |
||||
<para>When things are properly set up, we want to be able to assign the type property as a string, which a |
||||
<interfacename>PropertyEditor</interfacename> will behind the scenes convert into an actual |
||||
<classname>ExoticType</classname> instance:</para> |
||||
<programlisting><![CDATA[<bean id="sample" class="example.DependsOnExoticType"> |
||||
<property name="type" value="aNameForExoticType"/> |
||||
</bean>]]></programlisting> |
||||
<para>The <interfacename>PropertyEditor</interfacename> implementation could look similar to this:</para> |
||||
<programlisting><lineannotation>// converts string representation to <classname>ExoticType</classname> object</lineannotation><![CDATA[ |
||||
package example; |
||||
|
||||
public class ExoticTypeEditor extends PropertyEditorSupport { |
||||
|
||||
private String format; |
||||
|
||||
public void setFormat(String format) { |
||||
this.format = format; |
||||
} |
||||
|
||||
public void setAsText(String text) { |
||||
if (format != null && format.equals("upperCase")) { |
||||
text = text.toUpperCase(); |
||||
} |
||||
ExoticType type = new ExoticType(text); |
||||
setValue(type); |
||||
} |
||||
}]]></programlisting> |
||||
<para>Finally, we use <classname>CustomEditorConfigurer</classname> to register the new |
||||
<interfacename>PropertyEditor</interfacename> with the <interfacename>ApplicationContext</interfacename>, |
||||
which will then be able to use it as needed:</para> |
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> |
||||
<property name="customEditors"> |
||||
<map> |
||||
<entry key="example.ExoticType"> |
||||
<bean class="example.ExoticTypeEditor"> |
||||
<property name="format" value="upperCase"/> |
||||
</bean> |
||||
</entry> |
||||
</map> |
||||
</property> |
||||
</bean>]]></programlisting> |
||||
|
||||
<section id="beans-beans-conversion-customeditor-registration-per"> |
||||
<title>Using <interfacename>PropertyEditorRegistrars</interfacename></title> |
||||
|
||||
<para>Another mechanism for registering property editors with the Spring container is to create and use |
||||
a <interfacename>PropertyEditorRegistrar</interfacename>. This interface is particularly useful when you |
||||
need to use the same set of property editors in several different situations: write a corresponding |
||||
registrar and reuse that in each case. <literal>PropertyEditorRegistrars</literal> work in conjunction |
||||
with an interface called <interfacename>PropertyEditorRegistry</interfacename>, an interface |
||||
that is implemented by the Spring <interfacename>BeanWrapper</interfacename> (and |
||||
<interfacename>DataBinder</interfacename>). <literal>PropertyEditorRegistrars</literal> are particularly |
||||
convenient when used in conjunction with the <classname>CustomEditorConfigurer</classname> |
||||
(introduced <link linkend="beans-beans-conversion-customeditor-registration">here</link>), which exposes a |
||||
property called <methodname>setPropertyEditorRegistrars(..)</methodname>: |
||||
<literal>PropertyEditorRegistrars</literal> added to a <classname>CustomEditorConfigurer</classname> in this |
||||
fashion can easily be shared with <interfacename>DataBinder</interfacename> and Spring MVC |
||||
<interfacename>Controllers</interfacename>. Furthermore, it avoids the need for synchronization on custom |
||||
editors: a <interfacename>PropertyEditorRegistrar</interfacename> is expected to create fresh |
||||
<interfacename>PropertyEditor</interfacename> instances for each bean creation attempt.</para> |
||||
<para>Using a <interfacename>PropertyEditorRegistrar</interfacename> is perhaps best illustrated with an |
||||
example. First off, you need to create your own <interfacename>PropertyEditorRegistrar</interfacename> |
||||
implementation:</para> |
||||
|
||||
<programlisting><![CDATA[package com.foo.editors.spring; |
||||
|
||||
public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar { |
||||
|
||||
public void registerCustomEditors(PropertyEditorRegistry registry) { |
||||
|
||||
]]><lineannotation>// it is expected that new <interfacename>PropertyEditor</interfacename> instances are created</lineannotation><![CDATA[ |
||||
registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor()); |
||||
|
||||
]]><lineannotation>// you could register as many custom property editors as are required here...</lineannotation><![CDATA[ |
||||
} |
||||
}]]></programlisting> |
||||
<para>See also the <classname>org.springframework.beans.support.ResourceEditorRegistrar</classname> for an |
||||
example <interfacename>PropertyEditorRegistrar</interfacename> implementation. Notice how in its |
||||
implementation of the <methodname>registerCustomEditors(..)</methodname> method it creates new instances |
||||
of each property editor.</para> |
||||
<para>Next we configure a <classname>CustomEditorConfigurer</classname> and inject an |
||||
instance of our <classname>CustomPropertyEditorRegistrar</classname> into it:</para> |
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> |
||||
<property name="propertyEditorRegistrars"> |
||||
<list> |
||||
<ref bean="customPropertyEditorRegistrar"/> |
||||
</list> |
||||
</property> |
||||
</bean> |
||||
|
||||
<bean id="customPropertyEditorRegistrar" class="com.foo.editors.spring.CustomPropertyEditorRegistrar"/>]]></programlisting> |
||||
|
||||
<para>Finally, and in a bit of a departure from the focus of this chapter, for those of you using |
||||
<link linkend="mvc">Spring's MVC web framework</link>, using <interfacename>PropertyEditorRegistrars</interfacename> |
||||
in conjunction with data-binding <interfacename>Controllers</interfacename> (such as |
||||
<classname>SimpleFormController</classname>) can be very convenient. Find below an example of using a |
||||
<interfacename>PropertyEditorRegistrar</interfacename> in the implementation of an <methodname>initBinder(..)</methodname> |
||||
method:</para> |
||||
|
||||
<programlisting><![CDATA[public final class RegisterUserController extends SimpleFormController { |
||||
|
||||
private final PropertyEditorRegistrar customPropertyEditorRegistrar; |
||||
|
||||
public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) { |
||||
this.customPropertyEditorRegistrar = propertyEditorRegistrar; |
||||
} |
||||
|
||||
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception { |
||||
]]><emphasis role="bold">this.customPropertyEditorRegistrar.registerCustomEditors(binder);</emphasis><![CDATA[ |
||||
} |
||||
|
||||
]]><lineannotation>// other methods to do with registering a <classname>User</classname></lineannotation><![CDATA[ |
||||
}]]></programlisting> |
||||
|
||||
<para>This style of <interfacename>PropertyEditor</interfacename> registration can lead to concise code (the |
||||
implementation of <methodname>initBinder(..)</methodname> is just one line long!), and allows common |
||||
<interfacename>PropertyEditor</interfacename> registration code to be encapsulated in a class and then |
||||
shared amongst as many <interfacename>Controllers</interfacename> as needed.</para> |
||||
|
||||
</section> |
||||
|
||||
</section> |
||||
|
||||
</section> |
||||
</section> |
||||
|
||||
</chapter> |
||||
@ -0,0 +1,597 @@
@@ -0,0 +1,597 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<appendix id="extensible-xml"> |
||||
<title>Extensible XML authoring</title> |
||||
<section id="extensible-xml-introduction"> |
||||
<title>Introduction</title> |
||||
<para>Since version 2.0, Spring has featured a mechanism for schema-based extensions |
||||
to the basic Spring XML format for defining and configuring beans. This section is |
||||
devoted to detailing how you would go about writing your own custom XML bean definition |
||||
parsers and integrating such parsers into the Spring IoC container.</para> |
||||
<para>To facilitate the authoring of configuration files using a schema-aware XML editor, |
||||
Spring's extensible XML configuration mechanism is based on XML Schema. If you are |
||||
not familiar with Spring's current XML configuration extensions that come with the |
||||
standard Spring distribution, please first read the appendix entitled |
||||
<xref linkend="xsd-config"/>.</para> |
||||
<para>Creating new XML configuration extensions can be done by following these (relatively) |
||||
simple steps:</para> |
||||
<para> |
||||
<orderedlist numeration="arabic"> |
||||
<listitem> |
||||
<para><link linkend="extensible-xml-schema">Authoring</link> an XML schema to describe your custom element(s).</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><link linkend="extensible-xml-namespacehandler">Coding</link> a custom <interfacename>NamespaceHandler</interfacename> |
||||
implementation (this is an easy step, don't worry).</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><link linkend="extensible-xml-parser">Coding</link> one or more <interfacename>BeanDefinitionParser</interfacename> |
||||
implementations (this is where the real work is done).</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><link linkend="extensible-xml-registration">Registering</link> the above artifacts with Spring (this too is an easy step).</para> |
||||
</listitem> |
||||
</orderedlist> |
||||
</para> |
||||
<para>What follows is a description of each of these steps. For the example, we will create |
||||
an XML extension (a custom XML element) that allows us to configure objects of the type |
||||
<classname>SimpleDateFormat</classname> (from the <literal>java.text</literal> package) |
||||
in an easy manner. When we are done, we will be able to define bean definitions of type |
||||
<classname>SimpleDateFormat</classname> like this:</para> |
||||
<programlisting><![CDATA[<myns:dateformat id="dateFormat" |
||||
pattern="yyyy-MM-dd HH:mm" |
||||
lenient="true"/> |
||||
]]></programlisting> |
||||
<para><emphasis>(Don't worry about the fact that this example is very simple; much more |
||||
detailed examples follow afterwards. The intent in this first simple example is to walk |
||||
you through the basic steps involved.)</emphasis></para> |
||||
</section> |
||||
<section id="extensible-xml-schema"> |
||||
<title>Authoring the schema</title> |
||||
<para>Creating an XML configuration extension for use with Spring's IoC container |
||||
starts with authoring an XML Schema to describe the extension. What follows |
||||
is the schema we'll use to configure <classname>SimpleDateFormat</classname> |
||||
objects.</para> |
||||
<programlisting><lineannotation><!-- myns.xsd (inside package org/springframework/samples/xml) --></lineannotation><![CDATA[ |
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<xsd:schema xmlns="http://www.mycompany.com/schema/myns" |
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" |
||||
xmlns:beans="http://www.springframework.org/schema/beans" |
||||
targetNamespace="http://www.mycompany.com/schema/myns" |
||||
elementFormDefault="qualified" |
||||
attributeFormDefault="unqualified"> |
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"/> |
||||
|
||||
<xsd:element name="dateformat"> |
||||
<xsd:complexType> |
||||
<xsd:complexContent>]]> |
||||
<emphasis role="bold"><![CDATA[<xsd:extension base="beans:identifiedType">]]></emphasis><![CDATA[ |
||||
<xsd:attribute name="lenient" type="xsd:boolean"/> |
||||
<xsd:attribute name="pattern" type="xsd:string" use="required"/> |
||||
</xsd:extension> |
||||
</xsd:complexContent> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
|
||||
</xsd:schema>]]></programlisting> |
||||
<para>(The emphasized line contains an extension base for all tags that |
||||
will be identifiable (meaning they have an <literal>id</literal> attribute |
||||
that will be used as the bean identifier in the container). We are able to use this |
||||
attribute because we imported the Spring-provided <literal>'beans'</literal> |
||||
namespace.)</para> |
||||
<para>The above schema will be used to configure <classname>SimpleDateFormat</classname> |
||||
objects, directly in an XML application context file using the |
||||
<literal><myns:dateformat/></literal> element.</para> |
||||
<programlisting><![CDATA[<myns:dateformat id="dateFormat" |
||||
pattern="yyyy-MM-dd HH:mm" |
||||
lenient="true"/> |
||||
]]></programlisting> |
||||
<para>Note that after we've created the infrastructure classes, the above snippet of XML |
||||
will essentially be exactly the same as the following XML snippet. In other words, |
||||
we're just creating a bean in the container, identified by the name |
||||
<literal>'dateFormat'</literal> of type <classname>SimpleDateFormat</classname>, with a |
||||
couple of properties set.</para> |
||||
<programlisting><![CDATA[<bean id="dateFormat" class="java.text.SimpleDateFormat"> |
||||
<constructor-arg value="yyyy-HH-dd HH:mm"/> |
||||
<property name="lenient" value="true"/> |
||||
</bean>]]></programlisting> |
||||
<note> |
||||
<para>The schema-based approach to creating configuration format allows for |
||||
tight integration with an IDE that has a schema-aware XML editor. Using a properly |
||||
authored schema, you can use autocompletion to have a user choose between several |
||||
configuration options defined in the enumeration.</para> |
||||
</note> |
||||
</section> |
||||
<section id="extensible-xml-namespacehandler"> |
||||
<title>Coding a <interfacename>NamespaceHandler</interfacename></title> |
||||
<para>In addition to the schema, we need a <interfacename>NamespaceHandler</interfacename> |
||||
that will parse all elements of this specific namespace Spring encounters |
||||
while parsing configuration files. The <interfacename>NamespaceHandler</interfacename> |
||||
should in our case take care of the parsing of the <literal>myns:dateformat</literal> |
||||
element.</para> |
||||
<para>The <interfacename>NamespaceHandler</interfacename> interface is pretty simple in that |
||||
it features just three methods:</para> |
||||
<itemizedlist spacing="compact"> |
||||
<listitem> |
||||
<para><methodname>init()</methodname> - allows for initialization of |
||||
the <interfacename>NamespaceHandler</interfacename> and will be called by Spring |
||||
before the handler is used</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><methodname>BeanDefinition parse(Element, ParserContext)</methodname> - |
||||
called when Spring encounters a top-level element (not nested inside a bean definition |
||||
or a different namespace). This method can register bean definitions itself and/or |
||||
return a bean definition.</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para><methodname>BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext)</methodname> - |
||||
called when Spring encounters an attribute or nested element of a different namespace. |
||||
The decoration of one or more bean definitions is used for example with the |
||||
<link linkend="beans-factory-scopes">out-of-the-box scopes Spring 2.0 supports</link>. |
||||
We'll start by highlighting a simple example, without using decoration, after which |
||||
we will show decoration in a somewhat more advanced example.</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
<para>Although it is perfectly possible to code your own |
||||
<interfacename>NamespaceHandler</interfacename> for the entire namespace |
||||
(and hence provide code that parses each and every element in the namespace), |
||||
it is often the case that each top-level XML element in a Spring XML |
||||
configuration file results in a single bean definition (as in our |
||||
case, where a single <literal><myns:dateformat/></literal> element |
||||
results in a single <classname>SimpleDateFormat</classname> bean definition). |
||||
Spring features a number of convenience classes that support this scenario. |
||||
In this example, we'll make use the <classname>NamespaceHandlerSupport</classname> class:</para> |
||||
<programlisting><![CDATA[package org.springframework.samples.xml; |
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport; |
||||
|
||||
public class MyNamespaceHandler extends NamespaceHandlerSupport { |
||||
|
||||
public void init() {]]><emphasis role="bold"><![CDATA[ |
||||
registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser()); |
||||
]]></emphasis>} |
||||
}</programlisting> |
||||
<para>The observant reader will notice that there isn't actually a whole lot of |
||||
parsing logic in this class. Indeed... the <classname>NamespaceHandlerSupport</classname> |
||||
class has a built in notion of delegation. It supports the registration of any number |
||||
of <interfacename>BeanDefinitionParser</interfacename> instances, to which it will delegate |
||||
to when it needs to parse an element in its namespace. This clean separation of concerns |
||||
allows a <interfacename>NamespaceHandler</interfacename> to handle the orchestration |
||||
of the parsing of <emphasis>all</emphasis> of the custom elements in its namespace, |
||||
while delegating to <literal>BeanDefinitionParsers</literal> to do the grunt work of the |
||||
XML parsing; this means that each <interfacename>BeanDefinitionParser</interfacename> will |
||||
contain just the logic for parsing a single custom element, as we can see in the next step</para> |
||||
</section> |
||||
<section id="extensible-xml-parser"> |
||||
<title>Coding a <interfacename>BeanDefinitionParser</interfacename></title> |
||||
<para>A <interfacename>BeanDefinitionParser</interfacename> will be used if the |
||||
<interfacename>NamespaceHandler</interfacename> encounters an XML element of the type |
||||
that has been mapped to the specific bean definition parser (which is <literal>'dateformat'</literal> |
||||
in this case). In other words, the <interfacename>BeanDefinitionParser</interfacename> is |
||||
responsible for parsing <emphasis>one</emphasis> distinct top-level XML element defined in the |
||||
schema. In the parser, we'll have access to the XML element (and thus its subelements too) |
||||
so that we can parse our custom XML content, as can be seen in the following example:</para> |
||||
<programlisting><![CDATA[package org.springframework.samples.xml; |
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder; |
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; |
||||
import org.springframework.util.StringUtils; |
||||
import org.w3c.dom.Element; |
||||
|
||||
import java.text.SimpleDateFormat; |
||||
|
||||
public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { ]]><co id="extensible-xml-parser-simpledateformat-co-1"/><![CDATA[ |
||||
|
||||
protected Class getBeanClass(Element element) { |
||||
return SimpleDateFormat.class; ]]><co id="extensible-xml-parser-simpledateformat-co-2"/><![CDATA[ |
||||
} |
||||
|
||||
protected void doParse(Element element, BeanDefinitionBuilder bean) { |
||||
]]><lineannotation>// this will never be null since the schema explicitly requires that a value be supplied</lineannotation><![CDATA[ |
||||
String pattern = element.getAttribute("pattern"); |
||||
bean.addConstructorArg(pattern); |
||||
|
||||
]]><lineannotation>// this however is an optional property</lineannotation><![CDATA[ |
||||
String lenient = element.getAttribute("lenient"); |
||||
if (StringUtils.hasText(lenient)) { |
||||
bean.addPropertyValue("lenient", Boolean.valueOf(lenient)); |
||||
} |
||||
} |
||||
}]]></programlisting> |
||||
<calloutlist> |
||||
<callout arearefs="extensible-xml-parser-simpledateformat-co-1"> |
||||
<para>We use the Spring-provided <classname>AbstractSingleBeanDefinitionParser</classname> |
||||
to handle a lot of the basic grunt work of creating a <emphasis>single</emphasis> |
||||
<interfacename>BeanDefinition</interfacename>.</para> |
||||
</callout> |
||||
<callout arearefs="extensible-xml-parser-simpledateformat-co-2"> |
||||
<para>We supply the <classname>AbstractSingleBeanDefinitionParser</classname> superclass |
||||
with the type that our single <interfacename>BeanDefinition</interfacename> will represent.</para> |
||||
</callout> |
||||
</calloutlist> |
||||
<para>In this simple case, this is all that we need to do. The creation of our single |
||||
<interfacename>BeanDefinition</interfacename> is handled by the <classname>AbstractSingleBeanDefinitionParser</classname> |
||||
superclass, as is the extraction and setting of the bean definition's unique identifier.</para> |
||||
</section> |
||||
<section id="extensible-xml-registration"> |
||||
<title>Registering the handler and the schema</title> |
||||
<para>The coding is finished! All that remains to be done is to somehow make the Spring XML |
||||
parsing infrastructure aware of our custom element; we do this by registering our custom |
||||
<interfacename>namespaceHandler</interfacename> and custom XSD file in two special purpose |
||||
properties files. These properties files are both placed in a |
||||
<filename class="directory">'META-INF'</filename> directory in your application, and can, for |
||||
example, be distributed alongside your binary classes in a JAR file. The Spring XML parsing |
||||
infrastructurewill automatically pick up your new extension by consuming these special |
||||
properties files, the formats of which are detailed below.</para> |
||||
<section id="extensible-xml-registration-spring-handlers"> |
||||
<title><filename>'META-INF/spring.handlers'</filename></title> |
||||
<para>The properties file called <filename>'spring.handlers'</filename> contains a mapping |
||||
of XML Schema URIs to namespace handler classes. So for our example, we need to write the |
||||
following:</para> |
||||
<programlisting><![CDATA[http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler]]></programlisting> |
||||
<para><emphasis>(The <literal>':'</literal> character is a valid delimiter in the Java properties format, |
||||
and so the <literal>':'</literal> character in the URI needs to be escaped with a backslash.)</emphasis></para> |
||||
<para>The first part (the key) of the key-value pair is the URI associated with your custom namespace |
||||
extension, and needs to <emphasis>match exactly</emphasis> the value of the |
||||
<literal>'targetNamespace'</literal> attribute as specified in your custom XSD schema.</para> |
||||
</section> |
||||
<section id="extensible-xml-registration-spring-schemas"> |
||||
<title><filename>'META-INF/spring.schemas'</filename></title> |
||||
<para>The properties file called <filename>'spring.schemas'</filename> contains a mapping |
||||
of XML Schema locations (referred to along with the schema declaration in XML files |
||||
that use the schema as part of the <literal>'xsi:schemaLocation'</literal> attribute) |
||||
to <emphasis>classpath</emphasis> resources. This file is needed to prevent Spring from |
||||
absolutely having to use a default <interfacename>EntityResolver</interfacename> that requires |
||||
Internet access to retrieve the schema file. If you specify the mapping in this properties file, |
||||
Spring will search for the schema on the classpath (in this case <literal>'myns.xsd'</literal> |
||||
in the <literal>'org.springframework.samples.xml'</literal> package):</para> |
||||
<programlisting><![CDATA[http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd]]></programlisting> |
||||
<para>The upshot of this is that you are encouraged to deploy your XSD file(s) right alongside |
||||
the <interfacename>NamespaceHandler</interfacename> and <interfacename>BeanDefinitionParser</interfacename> |
||||
classes on the classpath.</para> |
||||
</section> |
||||
</section> |
||||
<section id="extensible-xml-using"> |
||||
<title>Using a custom extension in your Spring XML configuration</title> |
||||
<para>Using a custom extension that you yourself have implemented is no different from |
||||
using one of the 'custom' extensions that Spring provides straight out of the box. Find below |
||||
an example of using the custom <literal><dateformat/></literal> element developed in the |
||||
previous steps in a Spring XML configuration file.</para> |
||||
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?> |
||||
<beans xmlns="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns:myns="http://www.mycompany.com/schema/myns" |
||||
xsi:schemaLocation=" |
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd |
||||
http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd"> |
||||
|
||||
]]><lineannotation><!-- as a top-level bean --></lineannotation><![CDATA[ |
||||
<myns:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm" lenient="true"/> |
||||
|
||||
<bean id="jobDetailTemplate" abstract="true"> |
||||
<property name="dateFormat"> |
||||
]]><lineannotation><!-- as an inner bean --></lineannotation><![CDATA[ |
||||
<myns:dateformat pattern="HH:mm MM-dd-yyyy"/> |
||||
</property> |
||||
</bean> |
||||
|
||||
</beans>]]></programlisting> |
||||
</section> |
||||
<section id="extensible-xml-meat"> |
||||
<title>Meatier examples</title> |
||||
<para>Find below some much meatier examples of custom XML extensions.</para> |
||||
<section id="extensible-xml-custom-nested"> |
||||
<title>Nesting custom tags within custom tags</title> |
||||
<para>This example illustrates how you might go about writing the various artifacts |
||||
required to satisfy a target of the following configuration:</para> |
||||
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?> |
||||
<beans xmlns="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns:foo="http://www.foo.com/schema/component" |
||||
xsi:schemaLocation=" |
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd |
||||
http://www.foo.com/schema/component http://www.foo.com/schema/component/component.xsd"> |
||||
|
||||
]]><lineannotation><![CDATA[<foo:component id="bionic-family" name="Bionic-1"> |
||||
<foo:component name="Sport-1"/> |
||||
<foo:component name="Rock-1"/> |
||||
</foo:component>]]></lineannotation><![CDATA[ |
||||
|
||||
</beans>]]></programlisting> |
||||
<para>The above configuration actually nests custom extensions within each other. The class |
||||
that is actually configured by the above <literal><foo:component/></literal> |
||||
element is the <classname>Component</classname> class (shown directly below). Notice |
||||
how the <classname>Component</classname> class does <emphasis>not</emphasis> expose |
||||
a setter method for the <literal>'components'</literal> property; this makes it hard |
||||
(or rather impossible) to configure a bean definition for the <classname>Component</classname> |
||||
class using setter injection.</para> |
||||
<programlisting><![CDATA[package com.foo; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public class Component { |
||||
|
||||
private String name; |
||||
private List components = new ArrayList(); |
||||
|
||||
]]><lineannotation>// mmm, there is no setter method for the <literal>'components'</literal></lineannotation><![CDATA[ |
||||
public void addComponent(Component component) { |
||||
this.components.add(component); |
||||
} |
||||
|
||||
public List getComponents() { |
||||
return components; |
||||
} |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
}]]></programlisting> |
||||
<para>The typical solution to this issue is to create a custom <interfacename>FactoryBean</interfacename> |
||||
that exposes a setter property for the <literal>'components'</literal> property.</para> |
||||
<programlisting><![CDATA[package com.foo; |
||||
|
||||
import org.springframework.beans.factory.FactoryBean; |
||||
|
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
|
||||
public class ComponentFactoryBean implements FactoryBean { |
||||
|
||||
private Component parent; |
||||
private List children; |
||||
|
||||
public void setParent(Component parent) { |
||||
this.parent = parent; |
||||
} |
||||
|
||||
public void setChildren(List children) { |
||||
this.children = children; |
||||
} |
||||
|
||||
public Object getObject() throws Exception { |
||||
if (this.children != null && this.children.size() > 0) { |
||||
for (Iterator it = children.iterator(); it.hasNext();) { |
||||
Component childComponent = (Component) it.next(); |
||||
this.parent.addComponent(childComponent); |
||||
} |
||||
} |
||||
return this.parent; |
||||
} |
||||
|
||||
public Class getObjectType() { |
||||
return Component.class; |
||||
} |
||||
|
||||
public boolean isSingleton() { |
||||
return true; |
||||
} |
||||
}]]></programlisting> |
||||
<para>This is all very well, and does work nicely, but exposes a lot of Spring plumbing to the |
||||
end user. What we are going to do is write a custom extension that hides away all of this |
||||
Spring plumbing. If we stick to <link linkend="extensible-xml-introduction">the steps described |
||||
previously</link>, we'll start off by creating the XSD schema to define the structure of |
||||
our custom tag.</para> |
||||
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
|
||||
<xsd:schema xmlns="http://www.foo.com/schema/component" |
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" |
||||
targetNamespace="http://www.foo.com/schema/component" |
||||
elementFormDefault="qualified" |
||||
attributeFormDefault="unqualified"> |
||||
|
||||
<xsd:element name="component"> |
||||
<xsd:complexType> |
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded"> |
||||
<xsd:element ref="component"/> |
||||
</xsd:choice> |
||||
<xsd:attribute name="id" type="xsd:ID"/> |
||||
<xsd:attribute name="name" use="required" type="xsd:string"/> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
|
||||
</xsd:schema> |
||||
]]></programlisting> |
||||
<para>We'll then create a custom <interfacename>NamespaceHandler</interfacename>.</para> |
||||
<programlisting><![CDATA[package com.foo; |
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport; |
||||
|
||||
public class ComponentNamespaceHandler extends NamespaceHandlerSupport { |
||||
|
||||
public void init() { |
||||
registerBeanDefinitionParser("component", new ComponentBeanDefinitionParser()); |
||||
} |
||||
}]]></programlisting> |
||||
<para>Next up is the custom <interfacename>BeanDefinitionParser</interfacename>. Remember |
||||
that what we are creating is a <interfacename>BeanDefinition</interfacename> describing |
||||
a <classname>ComponentFactoryBean</classname>.</para> |
||||
<programlisting><![CDATA[package com.foo; |
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition; |
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder; |
||||
import org.springframework.beans.factory.support.ManagedList; |
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; |
||||
import org.springframework.beans.factory.xml.ParserContext; |
||||
import org.springframework.util.xml.DomUtils; |
||||
import org.w3c.dom.Element; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser { |
||||
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { |
||||
BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(ComponentFactoryBean.class); |
||||
BeanDefinitionBuilder parent = parseComponent(element); |
||||
factory.addPropertyValue("parent", parent.getBeanDefinition()); |
||||
|
||||
List childElements = DomUtils.getChildElementsByTagName(element, "component"); |
||||
if (childElements != null && childElements.size() > 0) { |
||||
parseChildComponents(childElements, factory); |
||||
} |
||||
return factory.getBeanDefinition(); |
||||
} |
||||
|
||||
private static BeanDefinitionBuilder parseComponent(Element element) { |
||||
BeanDefinitionBuilder component = BeanDefinitionBuilder.rootBeanDefinition(Component.class); |
||||
component.addPropertyValue("name", element.getAttribute("name")); |
||||
return component; |
||||
} |
||||
|
||||
private static void parseChildComponents(List childElements, BeanDefinitionBuilder factory) { |
||||
ManagedList children = new ManagedList(childElements.size()); |
||||
for (int i = 0; i < childElements.size(); ++i) { |
||||
Element childElement = (Element) childElements.get(i); |
||||
BeanDefinitionBuilder child = parseComponent(childElement); |
||||
children.add(child.getBeanDefinition()); |
||||
} |
||||
factory.addPropertyValue("children", children); |
||||
} |
||||
}]]></programlisting> |
||||
<para>Lastly, the various artifacts need to be registered with the Spring XML infrastructure.</para> |
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.handlers'</filename></lineannotation><![CDATA[ |
||||
http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler]]></programlisting> |
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.schemas'</filename></lineannotation><![CDATA[ |
||||
http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd]]></programlisting> |
||||
</section> |
||||
<section id="extensible-xml-custom-just-attributes"> |
||||
<title>Custom attributes on 'normal' elements</title> |
||||
<para>Writing your own custom parser and the associated artifacts isn't hard, but sometimes it |
||||
is not the right thing to do. Consider the scenario where you need to add metadata to already |
||||
existing bean definitions. In this case you certainly don't want to have to go off and write |
||||
your own entire custom extension; rather you just want to add an additional attribute |
||||
to the existing bean definition element.</para> |
||||
<para>By way of another example, let's say that the service class that you are defining a bean |
||||
definition for a service object that will (unknown to it) be accessing a clustered |
||||
<ulink url="http://jcp.org/en/jsr/detail?id=107">JCache</ulink>, and you want to ensure that |
||||
the named JCache instance is eagerly started within the surrounding cluster:</para> |
||||
<programlisting><![CDATA[<bean id="checkingAccountService" class="com.foo.DefaultCheckingAccountService" |
||||
]]><lineannotation><emphasis role="bold">jcache:cache-name="checking.account"></emphasis></lineannotation><![CDATA[ |
||||
]]><lineannotation><!-- other dependencies here... --></lineannotation><![CDATA[ |
||||
</bean>]]></programlisting> |
||||
<para>What we are going to do here is create another <interfacename>BeanDefinition</interfacename> |
||||
when the <literal>'jcache:cache-name'</literal> attribute is parsed; this |
||||
<interfacename>BeanDefinition</interfacename> will then initialize the named JCache |
||||
for us. We will also modify the existing <interfacename>BeanDefinition</interfacename> for the |
||||
<literal>'checkingAccountService'</literal> so that it will have a dependency on this |
||||
new JCache-initializing <interfacename>BeanDefinition</interfacename>.</para> |
||||
<programlisting><![CDATA[package com.foo; |
||||
|
||||
public class JCacheInitializer { |
||||
|
||||
private String name; |
||||
|
||||
public JCacheInitializer(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public void initialize() { |
||||
]]><lineannotation>// lots of JCache API calls to initialize the named cache...</lineannotation><![CDATA[ |
||||
} |
||||
}]]></programlisting> |
||||
<para>Now onto the custom extension. Firstly, the authoring of the XSD schema describing the |
||||
custom attribute (quite easy in this case).</para> |
||||
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
|
||||
<xsd:schema xmlns="http://www.foo.com/schema/jcache" |
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" |
||||
targetNamespace="http://www.foo.com/schema/jcache" |
||||
elementFormDefault="qualified"> |
||||
|
||||
<xsd:attribute name="cache-name" type="xsd:string"/> |
||||
|
||||
</xsd:schema> |
||||
]]></programlisting> |
||||
<para>Next, the associated <interfacename>NamespaceHandler</interfacename>.</para> |
||||
<programlisting><![CDATA[package com.foo; |
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport; |
||||
|
||||
public class JCacheNamespaceHandler extends NamespaceHandlerSupport { |
||||
|
||||
public void init() { |
||||
super.registerBeanDefinitionDecoratorForAttribute("cache-name", |
||||
new JCacheInitializingBeanDefinitionDecorator()); |
||||
} |
||||
} |
||||
]]></programlisting> |
||||
<para>Next, the parser. Note that in this case, because we are going to be parsing an XML |
||||
attribute, we write a <interfacename>BeanDefinitionDecorator</interfacename> rather than a |
||||
<interfacename>BeanDefinitionParser</interfacename>.</para> |
||||
<programlisting><![CDATA[package com.foo; |
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder; |
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition; |
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder; |
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator; |
||||
import org.springframework.beans.factory.xml.ParserContext; |
||||
import org.w3c.dom.Attr; |
||||
import org.w3c.dom.Node; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
|
||||
public class JCacheInitializingBeanDefinitionDecorator implements BeanDefinitionDecorator { |
||||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0]; |
||||
|
||||
public BeanDefinitionHolder decorate( |
||||
Node source, BeanDefinitionHolder holder, ParserContext ctx) { |
||||
String initializerBeanName = registerJCacheInitializer(source, ctx); |
||||
createDependencyOnJCacheInitializer(holder, initializerBeanName); |
||||
return holder; |
||||
} |
||||
|
||||
private void createDependencyOnJCacheInitializer(BeanDefinitionHolder holder, String initializerBeanName) { |
||||
AbstractBeanDefinition definition = ((AbstractBeanDefinition) holder.getBeanDefinition()); |
||||
String[] dependsOn = definition.getDependsOn(); |
||||
if (dependsOn == null) { |
||||
dependsOn = new String[]{initializerBeanName}; |
||||
} else { |
||||
List dependencies = new ArrayList(Arrays.asList(dependsOn)); |
||||
dependencies.add(initializerBeanName); |
||||
dependsOn = (String[]) dependencies.toArray(EMPTY_STRING_ARRAY); |
||||
} |
||||
definition.setDependsOn(dependsOn); |
||||
} |
||||
|
||||
private String registerJCacheInitializer(Node source, ParserContext ctx) { |
||||
String cacheName = ((Attr) source).getValue(); |
||||
String beanName = cacheName + "-initializer"; |
||||
if (!ctx.getRegistry().containsBeanDefinition(beanName)) { |
||||
BeanDefinitionBuilder initializer = BeanDefinitionBuilder.rootBeanDefinition(JCacheInitializer.class); |
||||
initializer.addConstructorArg(cacheName); |
||||
ctx.getRegistry().registerBeanDefinition(beanName, initializer.getBeanDefinition()); |
||||
} |
||||
return beanName; |
||||
} |
||||
} |
||||
]]></programlisting> |
||||
<para>Lastly, the various artifacts need to be registered with the Spring XML infrastructure.</para> |
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.handlers'</filename></lineannotation><![CDATA[ |
||||
http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler]]></programlisting> |
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.schemas'</filename></lineannotation><![CDATA[ |
||||
http\://www.foo.com/schema/jcache/jcache.xsd=com/foo/jcache.xsd]]></programlisting> |
||||
</section> |
||||
</section> |
||||
<section id="extensible-xml-resources"> |
||||
<title>Further Resources</title> |
||||
<para>Find below links to further resources concerning XML Schema and the extensible XML support |
||||
described in this chapter.</para> |
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>The <ulink url="http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/">XML Schema Part 1: Structures Second Edition</ulink></para> |
||||
</listitem> |
||||
<listitem> |
||||
<para>The <ulink url="http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/">XML Schema Part 2: Datatypes Second Edition</ulink></para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</section> |
||||
</appendix> |
||||
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
||||
<!-- |
||||
Licensed to the Apache Software Foundation (ASF) under one |
||||
or more contributor license agreements. See the NOTICE file |
||||
distributed with this work for additional information |
||||
regarding copyright ownership. The ASF licenses this file |
||||
to you under the Apache License, Version 2.0 (the |
||||
"License"); you may not use this file except in compliance |
||||
with the License. You may obtain a copy of the License at |
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
Unless required by applicable law or agreed to in writing, |
||||
software distributed under the License is distributed on an |
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
||||
KIND, either express or implied. See the License for the |
||||
specific language governing permissions and limitations |
||||
under the License. |
||||
--> |
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
||||
version='1.0'> |
||||
|
||||
<!-- Extensions --> |
||||
<xsl:param name="use.extensions">1</xsl:param> |
||||
<xsl:param name="tablecolumns.extension">0</xsl:param> |
||||
<xsl:param name="callout.extensions">1</xsl:param> |
||||
|
||||
<!-- Activate Graphics --> |
||||
<xsl:param name="admon.graphics" select="1"/> |
||||
<xsl:param name="admon.graphics.path">images/</xsl:param> |
||||
<xsl:param name="admon.graphics.extension">.gif</xsl:param> |
||||
<xsl:param name="callout.graphics" select="1" /> |
||||
<xsl:param name="callout.defaultcolumn">120</xsl:param> |
||||
<xsl:param name="callout.graphics.path">images/callouts/</xsl:param> |
||||
<xsl:param name="callout.graphics.extension">.gif</xsl:param> |
||||
|
||||
<xsl:param name="table.borders.with.css" select="1"/> |
||||
<xsl:param name="html.stylesheet">css/stylesheet.css</xsl:param> |
||||
<xsl:param name="html.stylesheet.type">text/css</xsl:param> |
||||
<xsl:param name="generate.toc">book toc,title</xsl:param> |
||||
|
||||
<xsl:param name="admonition.title.properties">text-align: left</xsl:param> |
||||
|
||||
<!-- Label Chapters and Sections (numbering) --> |
||||
<xsl:param name="chapter.autolabel" select="1"/> |
||||
<xsl:param name="section.autolabel" select="1"/> |
||||
<xsl:param name="section.autolabel.max.depth" select="1"/> |
||||
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/> |
||||
<xsl:param name="table.footnote.number.format" select="'1'"/> |
||||
|
||||
<!-- Remove "Chapter" from the Chapter titles... --> |
||||
<xsl:param name="local.l10n.xml" select="document('')"/> |
||||
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0"> |
||||
<l:l10n language="en"> |
||||
<l:context name="title-numbered"> |
||||
<l:template name="chapter" text="%n. %t"/> |
||||
<l:template name="section" text="%n %t"/> |
||||
</l:context> |
||||
</l:l10n> |
||||
</l:i18n> |
||||
</xsl:stylesheet> |
||||
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
||||
<!-- |
||||
Licensed to the Apache Software Foundation (ASF) under one |
||||
or more contributor license agreements. See the NOTICE file |
||||
distributed with this work for additional information |
||||
regarding copyright ownership. The ASF licenses this file |
||||
to you under the Apache License, Version 2.0 (the |
||||
"License"); you may not use this file except in compliance |
||||
with the License. You may obtain a copy of the License at |
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
Unless required by applicable law or agreed to in writing, |
||||
software distributed under the License is distributed on an |
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
||||
KIND, either express or implied. See the License for the |
||||
specific language governing permissions and limitations |
||||
under the License. |
||||
--> |
||||
|
||||
<t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0" |
||||
xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param" |
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> |
||||
|
||||
<!-- ==================================================================== --> |
||||
|
||||
<t:titlepage t:element="book" t:wrapper="div" class="titlepage"> |
||||
<t:titlepage-content t:side="recto"> |
||||
<productname/> |
||||
<title/> |
||||
<subtitle/> |
||||
<!-- <corpauthor/> |
||||
<authorgroup/> |
||||
<author/> |
||||
<mediaobject/> --> |
||||
<othercredit/> |
||||
<releaseinfo/> |
||||
<copyright/> |
||||
<legalnotice/> |
||||
<pubdate/> |
||||
<revision/> |
||||
<revhistory/> |
||||
<abstract/> |
||||
</t:titlepage-content> |
||||
|
||||
<t:titlepage-content t:side="verso"> |
||||
</t:titlepage-content> |
||||
|
||||
<t:titlepage-separator> |
||||
<hr/> |
||||
</t:titlepage-separator> |
||||
|
||||
<t:titlepage-before t:side="recto"> |
||||
</t:titlepage-before> |
||||
|
||||
<t:titlepage-before t:side="verso"> |
||||
</t:titlepage-before> |
||||
</t:titlepage> |
||||
|
||||
</t:templates> |
||||
@ -0,0 +1,429 @@
@@ -0,0 +1,429 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
||||
<!-- |
||||
Licensed to the Apache Software Foundation (ASF) under one |
||||
or more contributor license agreements. See the NOTICE file |
||||
distributed with this work for additional information |
||||
regarding copyright ownership. The ASF licenses this file |
||||
to you under the Apache License, Version 2.0 (the |
||||
"License"); you may not use this file except in compliance |
||||
with the License. You may obtain a copy of the License at |
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
Unless required by applicable law or agreed to in writing, |
||||
software distributed under the License is distributed on an |
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
||||
KIND, either express or implied. See the License for the |
||||
specific language governing permissions and limitations |
||||
under the License. |
||||
--> |
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format" |
||||
version='1.0'> |
||||
|
||||
<!-- Use nice graphics for admonitions --> |
||||
<xsl:param name="admon.graphics">'1'</xsl:param> |
||||
<xsl:param name="admon.graphics.path">@file.prefix@@dbf.xsl@/images/</xsl:param> |
||||
<xsl:param name="draft.watermark.image" select="'@file.prefix@@dbf.xsl@/images/draft.png'"/> |
||||
<xsl:param name="paper.type" select="'@paper.type@'"/> |
||||
|
||||
<xsl:param name="page.margin.top" select="'1cm'"/> |
||||
<xsl:param name="region.before.extent" select="'1cm'"/> |
||||
<xsl:param name="body.margin.top" select="'1.5cm'"/> |
||||
|
||||
<xsl:param name="body.margin.bottom" select="'1.5cm'"/> |
||||
<xsl:param name="region.after.extent" select="'1cm'"/> |
||||
<xsl:param name="page.margin.bottom" select="'1cm'"/> |
||||
<xsl:param name="title.margin.left" select="'0cm'"/> |
||||
|
||||
<!--################################################### |
||||
Header |
||||
################################################### --> |
||||
|
||||
<!-- More space in the center header for long text --> |
||||
<xsl:attribute-set name="header.content.properties"> |
||||
<xsl:attribute name="font-family"> |
||||
<xsl:value-of select="$body.font.family"/> |
||||
</xsl:attribute> |
||||
<xsl:attribute name="margin-left">-5em</xsl:attribute> |
||||
<xsl:attribute name="margin-right">-5em</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
|
||||
<!--################################################### |
||||
Table of Contents |
||||
################################################### --> |
||||
|
||||
<xsl:param name="generate.toc"> |
||||
book toc,title |
||||
</xsl:param> |
||||
|
||||
<!--################################################### |
||||
Custom Header |
||||
################################################### --> |
||||
|
||||
<xsl:template name="header.content"> |
||||
<xsl:param name="pageclass" select="''"/> |
||||
<xsl:param name="sequence" select="''"/> |
||||
<xsl:param name="position" select="''"/> |
||||
<xsl:param name="gentext-key" select="''"/> |
||||
|
||||
<xsl:variable name="Version"> |
||||
<xsl:choose> |
||||
<xsl:when test="//productname"> |
||||
<xsl:value-of select="//productname"/><xsl:text> </xsl:text> |
||||
</xsl:when> |
||||
<xsl:otherwise> |
||||
<xsl:text>please define productname in your docbook file!</xsl:text> |
||||
</xsl:otherwise> |
||||
</xsl:choose> |
||||
</xsl:variable> |
||||
|
||||
<xsl:choose> |
||||
<xsl:when test="$sequence='blank'"> |
||||
<xsl:choose> |
||||
<xsl:when test="$position='center'"> |
||||
<xsl:value-of select="$Version"/> |
||||
</xsl:when> |
||||
|
||||
<xsl:otherwise> |
||||
<!-- nop --> |
||||
</xsl:otherwise> |
||||
</xsl:choose> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$pageclass='titlepage'"> |
||||
<!-- nop: other titlepage sequences have no header --> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$position='center'"> |
||||
<xsl:value-of select="$Version"/> |
||||
</xsl:when> |
||||
|
||||
<xsl:otherwise> |
||||
<!-- nop --> |
||||
</xsl:otherwise> |
||||
</xsl:choose> |
||||
</xsl:template> |
||||
|
||||
<!--################################################### |
||||
Custom Footer |
||||
################################################### --> |
||||
|
||||
<xsl:template name="footer.content"> |
||||
<xsl:param name="pageclass" select="''"/> |
||||
<xsl:param name="sequence" select="''"/> |
||||
<xsl:param name="position" select="''"/> |
||||
<xsl:param name="gentext-key" select="''"/> |
||||
|
||||
<xsl:variable name="Version"> |
||||
<xsl:choose> |
||||
<xsl:when test="//releaseinfo"> |
||||
<xsl:value-of select="//releaseinfo"/> |
||||
</xsl:when> |
||||
<xsl:otherwise> |
||||
<!-- nop --> |
||||
</xsl:otherwise> |
||||
</xsl:choose> |
||||
</xsl:variable> |
||||
|
||||
<xsl:variable name="Title"> |
||||
<xsl:value-of select="//title"/> |
||||
</xsl:variable> |
||||
|
||||
<xsl:choose> |
||||
<xsl:when test="$sequence='blank'"> |
||||
<xsl:choose> |
||||
<xsl:when test="$double.sided != 0 and $position = 'left'"> |
||||
<xsl:value-of select="$Version"/> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$double.sided = 0 and $position = 'center'"> |
||||
<!-- nop --> |
||||
</xsl:when> |
||||
|
||||
<xsl:otherwise> |
||||
<fo:page-number/> |
||||
</xsl:otherwise> |
||||
</xsl:choose> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$pageclass='titlepage'"> |
||||
<!-- nop: other titlepage sequences have no footer --> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'"> |
||||
<fo:page-number/> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'"> |
||||
<fo:page-number/> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='right'"> |
||||
<fo:page-number/> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'"> |
||||
<xsl:value-of select="$Version"/> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'"> |
||||
<xsl:value-of select="$Version"/> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='left'"> |
||||
<xsl:value-of select="$Version"/> |
||||
</xsl:when> |
||||
|
||||
<xsl:when test="$position='center'"> |
||||
<xsl:value-of select="$Title"/> |
||||
</xsl:when> |
||||
|
||||
<xsl:otherwise> |
||||
<!-- nop --> |
||||
</xsl:otherwise> |
||||
</xsl:choose> |
||||
</xsl:template> |
||||
|
||||
<xsl:template match="processing-instruction('hard-pagebreak')"> |
||||
<fo:block break-before='page'/> |
||||
</xsl:template> |
||||
|
||||
<!--################################################### |
||||
Extensions |
||||
################################################### --> |
||||
|
||||
<!-- These extensions are required for table printing and other stuff --> |
||||
<xsl:param name="use.extensions">1</xsl:param> |
||||
<xsl:param name="tablecolumns.extension">0</xsl:param> |
||||
<xsl:param name="callout.extensions">1</xsl:param> |
||||
<xsl:param name="fop.extensions">1</xsl:param> |
||||
|
||||
<!--################################################### |
||||
Paper & Page Size |
||||
################################################### --> |
||||
|
||||
<!-- Paper type, no headers on blank pages, no double sided printing --> |
||||
<xsl:param name="double.sided">0</xsl:param> |
||||
<xsl:param name="headers.on.blank.pages">0</xsl:param> |
||||
<xsl:param name="footers.on.blank.pages">0</xsl:param> |
||||
|
||||
<!--################################################### |
||||
Fonts & Styles |
||||
################################################### --> |
||||
|
||||
<xsl:param name="hyphenate">false</xsl:param> |
||||
|
||||
<!-- Default Font size --> |
||||
<xsl:param name="body.font.master">11</xsl:param> |
||||
<xsl:param name="body.font.small">8</xsl:param> |
||||
|
||||
<!-- Line height in body text --> |
||||
<xsl:param name="line-height">1.4</xsl:param> |
||||
|
||||
<!-- Chapter title size --> |
||||
<xsl:attribute-set name="chapter.titlepage.recto.style"> |
||||
<xsl:attribute name="text-align">left</xsl:attribute> |
||||
<xsl:attribute name="font-weight">bold</xsl:attribute> |
||||
<xsl:attribute name="font-size"> |
||||
<xsl:value-of select="$body.font.master * 1.8"/> |
||||
<xsl:text>pt</xsl:text> |
||||
</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
|
||||
<!-- Why is the font-size for chapters hardcoded in the XSL FO templates? |
||||
Let's remove it, so this sucker can use our attribute-set only... --> |
||||
<xsl:template match="title" mode="chapter.titlepage.recto.auto.mode"> |
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" |
||||
xsl:use-attribute-sets="chapter.titlepage.recto.style"> |
||||
<xsl:call-template name="component.title"> |
||||
<xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/> |
||||
</xsl:call-template> |
||||
</fo:block> |
||||
</xsl:template> |
||||
|
||||
<!-- Sections 1, 2 and 3 titles have a small bump factor and padding --> |
||||
<xsl:attribute-set name="section.title.level1.properties"> |
||||
<xsl:attribute name="space-before.optimum">0.8em</xsl:attribute> |
||||
<xsl:attribute name="space-before.minimum">0.8em</xsl:attribute> |
||||
<xsl:attribute name="space-before.maximum">0.8em</xsl:attribute> |
||||
<xsl:attribute name="font-size"> |
||||
<xsl:value-of select="$body.font.master * 1.5"/> |
||||
<xsl:text>pt</xsl:text> |
||||
</xsl:attribute> |
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
<xsl:attribute-set name="section.title.level2.properties"> |
||||
<xsl:attribute name="space-before.optimum">0.6em</xsl:attribute> |
||||
<xsl:attribute name="space-before.minimum">0.6em</xsl:attribute> |
||||
<xsl:attribute name="space-before.maximum">0.6em</xsl:attribute> |
||||
<xsl:attribute name="font-size"> |
||||
<xsl:value-of select="$body.font.master * 1.25"/> |
||||
<xsl:text>pt</xsl:text> |
||||
</xsl:attribute> |
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
<xsl:attribute-set name="section.title.level3.properties"> |
||||
<xsl:attribute name="space-before.optimum">0.4em</xsl:attribute> |
||||
<xsl:attribute name="space-before.minimum">0.4em</xsl:attribute> |
||||
<xsl:attribute name="space-before.maximum">0.4em</xsl:attribute> |
||||
<xsl:attribute name="font-size"> |
||||
<xsl:value-of select="$body.font.master * 1.0"/> |
||||
<xsl:text>pt</xsl:text> |
||||
</xsl:attribute> |
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
|
||||
<!--################################################### |
||||
Tables |
||||
################################################### --> |
||||
|
||||
<!-- Some padding inside tables --> |
||||
<xsl:attribute-set name="table.cell.padding"> |
||||
<xsl:attribute name="padding-left">4pt</xsl:attribute> |
||||
<xsl:attribute name="padding-right">4pt</xsl:attribute> |
||||
<xsl:attribute name="padding-top">4pt</xsl:attribute> |
||||
<xsl:attribute name="padding-bottom">4pt</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
|
||||
<!-- Only hairlines as frame and cell borders in tables --> |
||||
<xsl:param name="table.frame.border.thickness">0.1pt</xsl:param> |
||||
<xsl:param name="table.cell.border.thickness">0.1pt</xsl:param> |
||||
|
||||
<!--################################################### |
||||
Labels |
||||
################################################### --> |
||||
|
||||
<!-- Label Chapters and Sections (numbering) --> |
||||
<xsl:param name="chapter.autolabel" select="1"/> |
||||
<xsl:param name="section.autolabel" select="1"/> |
||||
<xsl:param name="section.autolabel.max.depth" select="1"/> |
||||
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/> |
||||
<xsl:param name="table.footnote.number.format" select="'1'"/> |
||||
|
||||
<!--################################################### |
||||
Programlistings |
||||
################################################### --> |
||||
|
||||
<!-- Verbatim text formatting (programlistings) --> |
||||
<xsl:attribute-set name="monospace.verbatim.properties"> |
||||
<xsl:attribute name="font-size"> |
||||
<xsl:value-of select="$body.font.small * 1.0"/> |
||||
<xsl:text>pt</xsl:text> |
||||
</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
|
||||
<xsl:attribute-set name="verbatim.properties"> |
||||
<xsl:attribute name="space-before.minimum">1em</xsl:attribute> |
||||
<xsl:attribute name="space-before.optimum">1em</xsl:attribute> |
||||
<xsl:attribute name="space-before.maximum">1em</xsl:attribute> |
||||
<!-- alef: commented out because footnotes were screwed because of it --> |
||||
<!--<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>--> |
||||
|
||||
<xsl:attribute name="border-color">#444444</xsl:attribute> |
||||
<xsl:attribute name="border-style">solid</xsl:attribute> |
||||
<xsl:attribute name="border-width">0.1pt</xsl:attribute> |
||||
<xsl:attribute name="padding-top">0.5em</xsl:attribute> |
||||
<xsl:attribute name="padding-left">0.5em</xsl:attribute> |
||||
<xsl:attribute name="padding-right">0.5em</xsl:attribute> |
||||
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute> |
||||
<xsl:attribute name="margin-left">0.5em</xsl:attribute> |
||||
<xsl:attribute name="margin-right">0.5em</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
|
||||
<!-- Shade (background) programlistings --> |
||||
<xsl:param name="shade.verbatim">1</xsl:param> |
||||
<xsl:attribute-set name="shade.verbatim.style"> |
||||
<xsl:attribute name="background-color">#F0F0F0</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
|
||||
<xsl:attribute-set name="list.block.spacing"> |
||||
<xsl:attribute name="space-before.optimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-before.minimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-before.maximum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
|
||||
<xsl:attribute-set name="example.properties"> |
||||
<xsl:attribute name="space-before.minimum">0.5em</xsl:attribute> |
||||
<xsl:attribute name="space-before.optimum">0.5em</xsl:attribute> |
||||
<xsl:attribute name="space-before.maximum">0.5em</xsl:attribute> |
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="keep-together.within-column">always</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
|
||||
<!--################################################### |
||||
Title information for Figures, Examples etc. |
||||
################################################### --> |
||||
|
||||
<xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing"> |
||||
<xsl:attribute name="font-weight">normal</xsl:attribute> |
||||
<xsl:attribute name="font-style">italic</xsl:attribute> |
||||
<xsl:attribute name="font-size"> |
||||
<xsl:value-of select="$body.font.master"/> |
||||
<xsl:text>pt</xsl:text> |
||||
</xsl:attribute> |
||||
<xsl:attribute name="hyphenate">false</xsl:attribute> |
||||
<xsl:attribute name="space-before.minimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-before.optimum">0.1em</xsl:attribute> |
||||
<xsl:attribute name="space-before.maximum">0.1em</xsl:attribute> |
||||
</xsl:attribute-set> |
||||
|
||||
<!--################################################### |
||||
Callouts |
||||
################################################### --> |
||||
|
||||
<!-- don't use images for callouts --> |
||||
<xsl:param name="callout.graphics">0</xsl:param> |
||||
<xsl:param name="callout.unicode">1</xsl:param> |
||||
|
||||
<!-- Place callout marks at this column in annotated areas --> |
||||
<xsl:param name="callout.defaultcolumn">90</xsl:param> |
||||
|
||||
<!--################################################### |
||||
Misc |
||||
################################################### --> |
||||
|
||||
<!-- Placement of titles --> |
||||
<xsl:param name="formal.title.placement"> |
||||
figure after |
||||
example after |
||||
equation before |
||||
table before |
||||
procedure before |
||||
</xsl:param> |
||||
|
||||
<!-- Format Variable Lists as Blocks (prevents horizontal overflow) --> |
||||
<xsl:param name="variablelist.as.blocks">1</xsl:param> |
||||
|
||||
<xsl:param name="body.start.indent">0pt</xsl:param> |
||||
|
||||
<!-- Remove "Chapter" from the Chapter titles... --> |
||||
<xsl:param name="local.l10n.xml" select="document('')"/> |
||||
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0"> |
||||
<l:l10n language="en"> |
||||
<l:context name="title-numbered"> |
||||
<l:template name="chapter" text="%n. %t"/> |
||||
<l:template name="section" text="%n %t"/> |
||||
</l:context> |
||||
<l:context name="title"> |
||||
<l:template name="example" text="Example %n %t"/> |
||||
</l:context> |
||||
</l:l10n> |
||||
</l:i18n> |
||||
</xsl:stylesheet> |
||||
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
||||
<!-- |
||||
Licensed to the Apache Software Foundation (ASF) under one |
||||
or more contributor license agreements. See the NOTICE file |
||||
distributed with this work for additional information |
||||
regarding copyright ownership. The ASF licenses this file |
||||
to you under the Apache License, Version 2.0 (the |
||||
"License"); you may not use this file except in compliance |
||||
with the License. You may obtain a copy of the License at |
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
Unless required by applicable law or agreed to in writing, |
||||
software distributed under the License is distributed on an |
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
||||
KIND, either express or implied. See the License for the |
||||
specific language governing permissions and limitations |
||||
under the License. |
||||
--> |
||||
|
||||
<!DOCTYPE t:templates [ |
||||
<!ENTITY hsize0 "10pt"> |
||||
<!ENTITY hsize1 "12pt"> |
||||
<!ENTITY hsize2 "14.4pt"> |
||||
<!ENTITY hsize3 "17.28pt"> |
||||
<!ENTITY hsize4 "20.736pt"> |
||||
<!ENTITY hsize5 "24.8832pt"> |
||||
<!ENTITY hsize0space "7.5pt"> <!-- 0.75 * hsize0 --> |
||||
<!ENTITY hsize1space "9pt"> <!-- 0.75 * hsize1 --> |
||||
<!ENTITY hsize2space "10.8pt"> <!-- 0.75 * hsize2 --> |
||||
<!ENTITY hsize3space "12.96pt"> <!-- 0.75 * hsize3 --> |
||||
<!ENTITY hsize4space "15.552pt"> <!-- 0.75 * hsize4 --> |
||||
<!ENTITY hsize5space "18.6624pt"> <!-- 0.75 * hsize5 --> |
||||
]> |
||||
<t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0" |
||||
xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param" |
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format" |
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> |
||||
|
||||
<t:titlepage t:element="book" t:wrapper="fo:block"> |
||||
<t:titlepage-content t:side="recto"> |
||||
<title |
||||
t:named-template="division.title" |
||||
param:node="ancestor-or-self::book[1]" |
||||
text-align="center" |
||||
font-size="&hsize5;" |
||||
space-before="&hsize5space;" |
||||
font-weight="bold" |
||||
font-family="{$title.fontset}"/> |
||||
<subtitle |
||||
text-align="center" |
||||
font-size="&hsize4;" |
||||
space-before="&hsize4space;" |
||||
font-family="{$title.fontset}"/> |
||||
|
||||
<!-- <corpauthor space-before="0.5em" |
||||
font-size="&hsize2;"/> |
||||
<authorgroup space-before="0.5em" |
||||
font-size="&hsize2;"/> |
||||
<author space-before="0.5em" |
||||
font-size="&hsize2;"/> --> |
||||
|
||||
<mediaobject space-before="2em" space-after="2em"/> |
||||
<releaseinfo space-before="5em" font-size="&hsize2;"/> |
||||
<copyright space-before="1.5em" |
||||
font-weight="normal" |
||||
font-size="8"/> |
||||
<legalnotice space-before="5em" |
||||
font-weight="normal" |
||||
font-style="italic" |
||||
font-size="8"/> |
||||
<othercredit space-before="2em" |
||||
font-weight="normal" |
||||
font-size="8"/> |
||||
<pubdate space-before="0.5em"/> |
||||
<revision space-before="0.5em"/> |
||||
<revhistory space-before="0.5em"/> |
||||
<abstract space-before="0.5em" |
||||
text-align="start" |
||||
margin-left="0.5in" |
||||
margin-right="0.5in" |
||||
font-family="{$body.fontset}"/> |
||||
</t:titlepage-content> |
||||
|
||||
<t:titlepage-content t:side="verso"> |
||||
</t:titlepage-content> |
||||
|
||||
<t:titlepage-separator> |
||||
</t:titlepage-separator> |
||||
|
||||
<t:titlepage-before t:side="recto"> |
||||
</t:titlepage-before> |
||||
|
||||
<t:titlepage-before t:side="verso"> |
||||
</t:titlepage-before> |
||||
</t:titlepage> |
||||
|
||||
<!-- ==================================================================== --> |
||||
|
||||
</t:templates> |
||||