Added the Spring Framework reference documentation

This commit is contained in:
Thomas Risberg 2009-03-18 20:00:49 +00:00
parent d4ba002b00
commit abbdc1144a
91 changed files with 51186 additions and 0 deletions

View File

@ -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>

View File

@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 ejb.svg Page-1 -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="4.25667in"
height="2.64in" viewBox="0 0 306.48 190.08" xml:space="preserve" color-interpolation-filters="sRGB" class="st9">
<v:documentProperties v:langID="1033" v:metric="true"/>
<style type="text/css">
<![CDATA[
.st1 {fill:#f4f7f0;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st2 {fill:#000000;font-family:Arial;font-size:0.833336em}
.st3 {fill:#ecefe2;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st4 {visibility:visible}
.st5 {fill:#84877b;stroke:#84877b;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st6 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st7 {fill:#000000;font-family:Arial;font-size:0.75em}
.st8 {font-size:1em}
.st9 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
<title>Page-1</title>
<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
<g id="shape1-1" v:mID="1" v:groupContext="shape" transform="translate(0.24012,-0.24)">
<title>Box.1</title>
<desc>Application Server (e.g. JBoss, WebLogic)</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="153" cy="104.622" width="306" height="170.916"/>
<rect x="0" y="19.164" width="306" height="170.916" class="st1"/>
<text x="59.35" y="185.62" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Application Server (e.g. JBoss, WebLogic)</text> </g>
<g id="shape2-4" v:mID="2" v:groupContext="shape" transform="translate(30.1749,-23.3831)">
<title>Box.2</title>
<desc>Spring Core</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="49.8912" cy="159.506" width="99.79" height="61.1476"/>
<rect x="0" y="128.932" width="99.7826" height="61.1476" class="st3"/>
<text x="4" y="174.51" class="st2" v:langID="1033"><v:paragraph/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring Core </text> </g>
<g id="shape3-7" v:mID="3" v:groupContext="shape" transform="translate(161.223,-89.6263)">
<title>Box.3</title>
<desc>Spring Context</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="51.8869" cy="159.506" width="103.78" height="61.1476"/>
<rect x="0" y="128.932" width="103.774" height="61.1476" class="st3"/>
<text x="33.65" y="174.51" class="st2" v:langID="1033"><v:paragraph v:horizAlign="2"/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring Context</text> </g>
<g id="shape4-10" v:mID="4" v:groupContext="shape" transform="translate(6.89229,-150.773)">
<title>Box</title>
<desc>EJB Access layer using SlsbInvokers</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="69.8477" cy="170.547" width="139.71" height="39.0665"/>
<g id="shadow4-11" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="151.014" width="139.696" height="39.0665" class="st5"/>
</g>
<rect x="0" y="151.014" width="139.696" height="39.0665" class="st6"/>
<text x="22.83" y="167.85" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>EJB Access layer using <tspan
x="44.09" dy="1.2em" class="st8">SlsbInvokers</tspan></text> </g>
<g id="shape5-16" v:mID="5" v:groupContext="shape" transform="translate(161.888,-23.3831)">
<title>Box.4</title>
<desc>Spring DAO</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="51.2216" cy="159.506" width="102.46" height="61.1476"/>
<rect x="0" y="128.932" width="102.443" height="61.1476" class="st3"/>
<text x="45.09" y="174.51" class="st2" v:langID="1033"><v:paragraph v:horizAlign="2"/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring DAO</text> </g>
<g id="shape6-19" v:mID="6" v:groupContext="shape" transform="translate(26.5572,-60.768)">
<title>Box.5</title>
<desc>Spring-managed EJBs (using AbstractEnterpriseBean</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="81.1564" cy="149.315" width="162.33" height="81.5301"/>
<g id="shadow6-20" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="108.55" width="162.313" height="81.5301" class="st5"/>
</g>
<rect x="0" y="108.55" width="162.313" height="81.5301" class="st6"/>
<text x="36.12" y="152.02" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring-managed EJBs</text> </g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -0,0 +1,254 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 full.svg Page-1 -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="4.97167in"
height="3.59998in" viewBox="0 0 357.96 259.199" xml:space="preserve" color-interpolation-filters="sRGB" class="st9">
<v:documentProperties v:langID="1033" v:viewMarkup="false"/>
<style type="text/css">
<![CDATA[
.st1 {fill:#f4f7f0;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st2 {fill:#000000;font-family:Arial;font-size:0.666664em}
.st3 {fill:#ecefe2;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st4 {visibility:visible}
.st5 {fill:#84877b;stroke:#84877b;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st6 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st7 {fill:#000000;font-family:Arial;font-size:0.499992em}
.st8 {font-size:1em}
.st9 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
<title>Page-1</title>
<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
<g id="shape1-1" v:mID="1" v:groupContext="shape" transform="translate(3.12,-11.3134)">
<title>Box.1</title>
<desc>Servlet Container (Tomcat / Jetty)</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="176.4" cy="140.913" width="352.8" height="236.571"/>
<rect x="0" y="22.6271" width="352.8" height="236.571" class="st1"/>
<text x="116.6" y="248.91" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Servlet Container (Tomcat / Jetty)<v:newlineChar/><v:newlineChar/></text> </g>
<g id="shape2-4" v:mID="2" v:groupContext="shape" transform="translate(16.08,-37.4777)">
<title>Box.2</title>
<desc>Spring Core</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="81.9" cy="239.778" width="163.8" height="38.8414"/>
<rect x="0" y="220.357" width="163.8" height="38.8414" class="st3"/>
<text x="60.56" y="246.98" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/>Spring Core</text> </g>
<g id="shape3-7" v:mID="3" v:groupContext="shape" transform="translate(180.24,-37.4777)">
<title>Box.3</title>
<desc>Spring DAO</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="81.9" cy="239.778" width="163.81" height="38.8414"/>
<rect x="0" y="220.357" width="163.8" height="38.8414" class="st3"/>
<text x="60.56" y="246.98" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/>Spring DAO</text> </g>
<g id="shape4-10" v:mID="4" v:groupContext="shape" transform="translate(180.24,-74.7955)">
<title>Box.4</title>
<desc>Spring ORM</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="81.9" cy="240.395" width="163.8" height="37.6071"/>
<rect x="0" y="221.591" width="163.8" height="37.6071" class="st3"/>
<text x="11" y="238" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/> Spring ORM <v:newlineChar/></text> </g>
<g id="shape5-13" v:mID="5" v:groupContext="shape" transform="translate(16.44,-143.999)">
<title>Box.5</title>
<desc>Spring Web</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="163.8" cy="241.199" width="327.6" height="36"/>
<rect x="0" y="223.199" width="327.6" height="36" class="st3"/>
<text x="142.9" y="243.6" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring Web</text> </g>
<g id="shape7-16" v:mID="7" v:groupContext="shape" transform="translate(16.26,-74.7955)">
<title>Box.7</title>
<desc>Spring AOP</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="81.9" cy="240.395" width="163.8" height="37.6071"/>
<rect x="0" y="221.591" width="163.8" height="37.6071" class="st3"/>
<text x="4" y="238" class="st2" v:langID="1033"><v:paragraph/><v:tabList/> Spring AOP<v:newlineChar/></text> </g>
<g id="shape9-19" v:mID="9" v:groupContext="shape" transform="translate(114,-65.4848)">
<title>Box</title>
<desc>Hibernate mappings Custom Hibernate DAOs</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="72.45" cy="245.484" width="144.91" height="27.4286"/>
<g id="shadow9-20" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="231.77" width="144.9" height="27.4286" class="st5"/>
</g>
<rect x="0" y="231.77" width="144.9" height="27.4286" class="st6"/>
<text x="45.6" y="243.68" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hibernate mappings<v:newlineChar/><tspan
x="39.44" dy="1.2em" class="st8">Custom Hibernate DAOs</tspan></text> </g>
<g id="shape10-25" v:mID="10" v:groupContext="shape" transform="translate(16.44,-179.999)">
<title>Box.10</title>
<desc>Spring Web MVC</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="163.8" cy="246.052" width="327.6" height="26.2929"/>
<rect x="0" y="232.906" width="327.6" height="26.2929" class="st3"/>
<text x="132.9" y="248.45" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring Web MVC</text> </g>
<g id="shape6-28" v:mID="6" v:groupContext="shape" transform="translate(20.4,-211.542)">
<title>Box.6</title>
<desc>Form Controllers handling form interaction</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="36" cy="236.81" width="72" height="44.7771"/>
<g id="shadow6-29" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="214.421" width="72" height="44.7771" class="st5"/>
</g>
<rect x="0" y="214.421" width="72" height="44.7771" class="st6"/>
<text x="13.66" y="231.41" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Form Controllers <tspan
x="17.82" dy="1.2em" class="st8">handling form </tspan><tspan x="22.16" dy="1.2em" class="st8">interaction</tspan></text> </g>
<g id="shape11-35" v:mID="11" v:groupContext="shape" transform="translate(102.48,-211.679)">
<title>Box.11</title>
<desc>Multipart Resolver to handle file uploads</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="36" cy="236.81" width="72" height="44.7771"/>
<g id="shadow11-36" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="214.421" width="72" height="44.7771" class="st5"/>
</g>
<rect x="0" y="214.421" width="72" height="44.7771" class="st6"/>
<text x="11.83" y="235.01" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Multipart Resolver<v:newlineChar/><tspan
x="7.65" dy="1.2em" class="st8">to handle file uploads</tspan></text> </g>
<g id="shape12-41" v:mID="12" v:groupContext="shape" transform="translate(181.68,-211.679)">
<title>Box.12</title>
<desc>Dynamic binding of data to the domain model</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="36" cy="236.81" width="72" height="44.7771"/>
<g id="shadow12-42" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="214.421" width="72" height="44.7771" class="st5"/>
</g>
<rect x="0" y="214.421" width="72" height="44.7771" class="st6"/>
<text x="10.49" y="231.41" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Dynamic binding of <tspan
x="11.15" dy="1.2em" class="st8">data to the domain </tspan><tspan x="27.83" dy="1.2em" class="st8">model</tspan></text> </g>
<g id="shape13-48" v:mID="13" v:groupContext="shape" transform="translate(263.76,-211.679)">
<title>Box.13</title>
<desc>Integration with JSP, Velocity, XSLT, PDF, Excel</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="36" cy="236.81" width="72" height="44.7771"/>
<g id="shadow13-49" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="214.421" width="72" height="44.7771" class="st5"/>
</g>
<rect x="0" y="214.421" width="72" height="44.7771" class="st6"/>
<text x="8.49" y="231.41" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Integration with JSP, <tspan
x="7.83" dy="1.2em" class="st8">Velocity</tspan>, XSLT, PDF, <tspan x="28.66" dy="1.2em" class="st8">Excel</tspan></text> </g>
<g id="shape15-55" v:mID="15" v:groupContext="shape" transform="translate(16.44,-112.319)">
<title>Box.15</title>
<desc>Spring Context</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="163.8" cy="243.359" width="327.6" height="31.68"/>
<rect x="0" y="227.519" width="327.6" height="31.68" class="st3"/>
<text x="137.34" y="245.76" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring Context</text> </g>
<g id="shape8-58" v:mID="8" v:groupContext="shape" transform="translate(114,-138.239)">
<title>Box.8</title>
<desc>Declarative transaction management for POJOs</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="72" cy="251.999" width="144" height="14.4"/>
<g id="shadow8-59" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="244.799" width="144" height="14.4" class="st5"/>
</g>
<rect x="0" y="244.799" width="144" height="14.4" class="st6"/>
<text x="8.31" y="253.8" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Declarative transaction management for POJOs</text> </g>
<g id="shape14-63" v:mID="14" v:groupContext="shape" transform="translate(114,-107.999)">
<title>Box.14</title>
<desc>Custom business logic</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="72" cy="251.999" width="144" height="14.4"/>
<g id="shadow14-64" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="244.799" width="144" height="14.4" class="st5"/>
</g>
<rect x="0" y="244.799" width="144" height="14.4" class="st6"/>
<text x="41.99" y="253.8" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Custom business logic</text> </g>
<g id="shape16-68" v:mID="16" v:groupContext="shape" transform="translate(0.24,-107.999)">
<title>Box.16</title>
<desc>Sending Email</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="23.04" cy="231.839" width="46.08" height="54.72"/>
<g id="shadow16-69" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="204.479" width="46.08" height="54.72" class="st5"/>
</g>
<rect x="0" y="204.479" width="46.08" height="54.72" class="st6"/>
<text x="12.04" y="230.04" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Sending <tspan
x="15.55" dy="1.2em" class="st8">Email</tspan></text> </g>
<g id="shape17-74" v:mID="17" v:groupContext="shape" transform="translate(309.84,-107.999)">
<title>Box.17</title>
<desc>Remote access via Hession, Burlap, SOAP</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="23.04" cy="231.839" width="46.08" height="54.72"/>
<g id="shadow17-75" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="204.479" width="46.08" height="54.72" class="st5"/>
</g>
<rect x="0" y="204.479" width="46.08" height="54.72" class="st6"/>
<text x="12.55" y="222.84" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Remote <tspan
x="9.04" dy="1.2em" class="st8">access via<v:newlineChar/></tspan><tspan x="11.38" dy="1.2em" class="st8">Hession</tspan>, <tspan
x="4.38" dy="1.2em" class="st8">Burlap</tspan>, SOAP</text> </g>
<g id="shape18-82" v:mID="18" v:groupContext="shape" transform="translate(114,-172.799)">
<title>Box.18</title>
<desc>WebApplicationContext providing e.g. messaging</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="72" cy="251.999" width="144" height="14.4"/>
<g id="shadow18-83" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="244.799" width="144" height="14.4" class="st5"/>
</g>
<rect x="0" y="244.799" width="144" height="14.4" class="st6"/>
<text x="6.63" y="253.8" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>WebApplicationContext providing e.g. messaging</text> </g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 remoting.svg Page-1 -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="4.70667in"
height="2.65333in" viewBox="0 0 338.88 191.04" xml:space="preserve" color-interpolation-filters="sRGB" class="st9">
<v:documentProperties v:langID="1033" v:metric="true"/>
<style type="text/css">
<![CDATA[
.st1 {fill:#f4f7f0;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st2 {fill:#000000;font-family:Arial;font-size:0.75em}
.st3 {fill:#ecefe2;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st4 {visibility:visible}
.st5 {fill:#84877b;stroke:#84877b;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st6 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st7 {fill:#000000;font-family:Arial;font-size:0.666664em}
.st8 {font-size:1em}
.st9 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
<title>Page-1</title>
<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="8.99999"
v:shadowOffsetY="-8.99999"/>
<g id="shape1-1" v:mID="1" v:groupContext="shape" transform="translate(0.240333,-10.8)">
<title>Box.1</title>
<desc>Servlet Container (e.g. Tomcat / Jetty)</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
<v:textRect cx="169.199" cy="126.24" width="338.4" height="129.6"/>
<rect x="0" y="61.4399" width="338.4" height="129.6" class="st1"/>
<text x="93.17" y="177.54" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Servlet Container (e.g. Tomcat / Jetty)<v:newlineChar/><v:newlineChar/></text> </g>
<g id="shape2-4" v:mID="2" v:groupContext="shape" transform="translate(12.326,-37.8001)">
<title>Box.2</title>
<desc>Spring Core</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
<v:textRect cx="78.5567" cy="158.64" width="157.12" height="64.7999"/>
<rect x="0" y="126.24" width="157.114" height="64.7999" class="st3"/>
<text x="54.54" y="177.54" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Spring Core</text> </g>
<g id="shape3-7" v:mID="3" v:groupContext="shape" transform="translate(169.44,-37.8001)">
<title>Box.3</title>
<desc>Spring Context</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
<v:textRect cx="78.5567" cy="158.64" width="157.12" height="64.7999"/>
<rect x="0" y="126.24" width="157.114" height="64.7999" class="st3"/>
<text x="48.78" y="177.54" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Spring Context </text> </g>
<g id="shape4-10" v:mID="4" v:groupContext="shape" transform="translate(8.09603,-151.2)">
<title>Box.10</title>
<desc>JAX RPC client</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
<v:textRect cx="38.3717" cy="171.24" width="76.75" height="39.6"/>
<g id="shadow4-11" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="151.44" width="76.7442" height="39.6" class="st5"/>
</g>
<rect x="0" y="151.44" width="76.7442" height="39.6" class="st6"/>
<text x="11.03" y="173.64" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>JAX RPC client</text> </g>
<g id="shape5-15" v:mID="5" v:groupContext="shape" transform="translate(18.9732,-97.2)">
<title>Box.4</title>
<desc>Transprarent remote access (using remote package)</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
<v:textRect cx="150.466" cy="176.64" width="300.94" height="28.8"/>
<g id="shadow5-16" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="162.24" width="300.934" height="28.8" class="st5"/>
</g>
<rect x="0" y="162.24" width="300.934" height="28.8" class="st6"/>
<text x="58.65" y="179.04" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Transp<tspan
class="st8" v:langID="2057">ar</tspan>ent remote access (using remote package)</text> </g>
<g id="shape6-21" v:mID="6" v:groupContext="shape" transform="translate(18.9732,-68.4)">
<title>Box</title>
<desc>Custom logic contained by beans</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
<v:textRect cx="150.466" cy="176.64" width="300.94" height="28.8"/>
<g id="shadow6-22" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="162.24" width="300.934" height="28.8" class="st5"/>
</g>
<rect x="0" y="162.24" width="300.934" height="28.8" class="st6"/>
<text x="91.55" y="179.04" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Custom logic contained by beans</text> </g>
<g id="shape7-26" v:mID="7" v:groupContext="shape" transform="translate(96.9259,-151.2)">
<title>Box.5</title>
<desc>Hessian client</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
<v:textRect cx="36.1057" cy="171.24" width="72.22" height="39.6"/>
<g id="shadow7-27" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="151.44" width="72.212" height="39.6" class="st5"/>
</g>
<rect x="0" y="151.44" width="72.212" height="39.6" class="st6"/>
<text x="11.2" y="173.64" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hessian client</text> </g>
<g id="shape8-31" v:mID="8" v:groupContext="shape" transform="translate(184.094,-151.2)">
<title>Box.6</title>
<desc>Burlap client</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
<v:textRect cx="33.6885" cy="171.24" width="67.38" height="39.6"/>
<g id="shadow8-32" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="151.44" width="67.3778" height="39.6" class="st5"/>
</g>
<rect x="0" y="151.44" width="67.3778" height="39.6" class="st6"/>
<text x="11.69" y="173.64" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Burlap client</text> </g>
<g id="shape9-36" v:mID="9" v:groupContext="shape" transform="translate(266.126,-151.2)">
<title>Box.7</title>
<desc>RMI client</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
<v:textRect cx="33.6885" cy="171.24" width="67.38" height="39.6"/>
<g id="shadow9-37" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="151.44" width="67.3778" height="39.6" class="st5"/>
</g>
<rect x="0" y="151.44" width="67.3778" height="39.6" class="st6"/>
<text x="26.37" y="168.84" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>RMI<v:newlineChar/><tspan
x="24.36" dy="1.2em" class="st8">client</tspan></text> </g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 spring-overview.svg Page-1 -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="8.26772in"
height="11.6929in" viewBox="0 0 595.276 841.89" xml:space="preserve" color-interpolation-filters="sRGB" class="st5">
<v:documentProperties v:langID="1033" v:viewMarkup="false"/>
<style type="text/css">
<![CDATA[
.st1 {fill:#969696;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st2 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st3 {fill:#000000;font-family:Arial;font-size:2.50001em;font-weight:bold}
.st4 {font-size:0.333333em;font-weight:normal}
.st5 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
<v:userDefs>
<v:ud v:nameU="SchemeName" v:val="VT4(Default)"/>
</v:userDefs>
<title>Page-1</title>
<v:pageProperties v:drawingScale="0.0393701" v:pageScale="0.0393701" v:drawingUnits="24" v:shadowOffsetX="8.50394"
v:shadowOffsetY="-8.50394"/>
<v:layer v:name="Connector" v:index="0"/>
<g id="group9-1" transform="translate(549.921,-255.118) scale(-1,1)" v:mID="9" v:groupContext="group">
<v:userDefs>
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<title>3-D box.9</title>
<desc>Core The IoC container</desc>
<g id="shape10-2" v:mID="10" v:groupContext="shape" transform="translate(0,14.1732)">
<title>Sheet.10</title>
<path d="M0 827.72 L521.57 827.72 L507.4 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
</g>
<g id="shape11-4" v:mID="11" v:groupContext="shape" transform="translate(-14.1732,0)">
<title>Sheet.11</title>
<path d="M0 856.06 L14.17 841.89 L14.17 756.85 L0 771.02 L0 856.06 Z" class="st1"/>
</g>
<g id="shape12-6" v:mID="12" v:groupContext="shape">
<title>Sheet.12</title>
<rect x="0" y="756.85" width="521.575" height="85.0394" class="st2"/>
</g>
<g id="shape9-8" v:mID="9" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="260.787" cy="799.37" width="521.58" height="85.0394"/>
<text x="-294.97" y="797.57" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>Core<v:newlineChar/><v:newlineChar/><tspan
x="-300.54" dy="2.76em" class="st4">The IoC container</tspan></text> </g>
</g>
<g id="group1-11" transform="translate(269.291,-368.504) scale(-1,1)" v:mID="1" v:groupContext="group">
<v:userDefs>
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<title>3-D box.1</title>
<desc>AOP Spring AOP AspectJ integration</desc>
<g id="shape2-12" v:mID="2" v:groupContext="shape" transform="translate(0,14.1732)">
<title>Sheet.2</title>
<path d="M0 827.72 L240.94 827.72 L226.77 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
</g>
<g id="shape3-14" v:mID="3" v:groupContext="shape" transform="translate(-14.1732,0)">
<title>Sheet.3</title>
<path d="M0 856.06 L14.17 841.89 L14.17 756.85 L0 771.02 L0 856.06 Z" class="st1"/>
</g>
<g id="shape4-16" v:mID="4" v:groupContext="shape">
<title>Sheet.4</title>
<rect x="0" y="756.85" width="240.945" height="85.0394" class="st2"/>
</g>
<g id="shape1-18" v:mID="1" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="120.472" cy="799.37" width="240.95" height="85.0394"/>
<text x="-152.97" y="791.57" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>AOP<v:newlineChar/><v:newlineChar/><tspan
x="-146.87" dy="2.76em" class="st4">Spring AOP<v:newlineChar/></tspan><tspan x="-162.99" dy="1.2em"
class="st4">AspectJ integration</tspan></text> </g>
</g>
<g id="group5-22" transform="translate(133.228,-481.89) scale(-1,1)" v:mID="5" v:groupContext="group">
<v:userDefs>
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<title>3-D box.5</title>
<desc>DAO Spring JDBC Transaction management</desc>
<g id="shape6-23" v:mID="6" v:groupContext="shape" transform="translate(0,14.1732)">
<title>Sheet.6</title>
<path d="M0 827.72 L104.88 827.72 L90.71 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
</g>
<g id="shape7-25" v:mID="7" v:groupContext="shape" transform="translate(-14.1732,0)">
<title>Sheet.7</title>
<path d="M0 856.06 L14.17 841.89 L14.17 657.64 L0 671.81 L0 856.06 Z" class="st1"/>
</g>
<g id="shape8-27" v:mID="8" v:groupContext="shape">
<title>Sheet.8</title>
<rect x="0" y="657.638" width="104.882" height="184.252" class="st2"/>
</g>
<g id="shape5-29" v:mID="5" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="52.4409" cy="749.764" width="104.89" height="184.252"/>
<text x="-85.76" y="735.96" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>DAO<v:newlineChar/><v:newlineChar/><tspan
x="-81.33" dy="2.76em" class="st4">Spring JDBC<v:newlineChar/></tspan><tspan x="-78.56" dy="1.2em"
class="st4">Transaction </tspan><tspan x="-81.62" dy="1.2em" class="st4">management</tspan></text> </g>
</g>
<g id="group13-34" transform="translate(413.858,-368.504) scale(-1,1)" v:mID="13" v:groupContext="group">
<v:userDefs>
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<title>3-D box.13</title>
<desc>JEE JMX JMS JCA Remoting EJBs Email</desc>
<g id="shape14-35" v:mID="14" v:groupContext="shape" transform="translate(0,14.1732)">
<title>Sheet.14</title>
<path d="M0 827.72 L113.39 827.72 L99.21 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
</g>
<g id="shape15-37" v:mID="15" v:groupContext="shape" transform="translate(-14.1732,0)">
<title>Sheet.15</title>
<path d="M0 856.06 L14.17 841.89 L14.17 544.25 L0 558.43 L0 856.06 Z" class="st1"/>
</g>
<g id="shape16-39" v:mID="16" v:groupContext="shape">
<title>Sheet.16</title>
<rect x="0" y="544.252" width="113.386" height="297.638" class="st2"/>
</g>
<g id="shape13-41" v:mID="13" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="56.6929" cy="693.071" width="113.39" height="297.638"/>
<text x="-85.04" y="661.27" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>JEE<v:newlineChar/><v:newlineChar/><tspan
x="-66.69" dy="2.76em" class="st4">JMX<v:newlineChar/></tspan><tspan x="-66.69" dy="1.2em" class="st4">JMS<v:newlineChar/></tspan><tspan
x="-66.13" dy="1.2em" class="st4">JCA<v:newlineChar/></tspan><tspan x="-78.08" dy="1.2em" class="st4">Remoting<v:newlineChar/></tspan><tspan
x="-68.36" dy="1.2em" class="st4">EJBs<v:newlineChar/></tspan><tspan x="-69.19" dy="1.2em" class="st4">Email</tspan></text> </g>
</g>
<g id="group17-49" transform="translate(552.756,-368.504) scale(-1,1)" v:mID="17" v:groupContext="group">
<v:userDefs>
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<title>3-D box.17</title>
<desc>Web Spring Web MVC Framework Integration Struts WebWork Tapes...</desc>
<g id="shape18-50" v:mID="18" v:groupContext="shape" transform="translate(0,14.1732)">
<title>Sheet.18</title>
<path d="M0 827.72 L113.39 827.72 L99.21 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
</g>
<g id="shape19-52" v:mID="19" v:groupContext="shape" transform="translate(-14.1732,0)">
<title>Sheet.19</title>
<path d="M0 856.06 L14.17 841.89 L14.17 544.25 L0 558.43 L0 856.06 Z" class="st1"/>
</g>
<g id="shape20-54" v:mID="20" v:groupContext="shape">
<title>Sheet.20</title>
<rect x="0" y="544.252" width="113.386" height="297.638" class="st2"/>
</g>
<g id="shape17-56" v:mID="17" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="56.6929" cy="693.071" width="113.39" height="297.638"/>
<text x="-88.35" y="613.27" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>Web<v:newlineChar/><v:newlineChar/><tspan
x="-95.31" dy="2.76em" class="st4">Spring Web MVC<v:newlineChar/></tspan><tspan x="-106.71" dy="1.2em"
class="st4">Framework Integration<v:newlineChar/></tspan><tspan x="-69.75" dy="1.2em" class="st4">Struts<v:newlineChar/></tspan><tspan
x="-78.63" dy="1.2em" class="st4">WebWork<v:newlineChar/></tspan><tspan x="-76.14" dy="1.2em"
class="st4">Tapestry<v:newlineChar/></tspan><tspan x="-65.57" dy="1.2em" class="st4">JSF<v:newlineChar/></tspan><tspan
x="-97.82" dy="1.2em" class="st4">Rich View Support<v:newlineChar/></tspan><tspan x="-68.36" dy="1.2em"
class="st4">JSPs<v:newlineChar/></tspan><tspan x="-74.19" dy="1.2em" class="st4">Velocity<v:newlineChar/></tspan><tspan
x="-82.52" dy="1.2em" class="st4">FreeMarker<v:newlineChar/></tspan><tspan x="-66.69" dy="1.2em"
class="st4">PDF<v:newlineChar/></tspan><tspan x="-90.59" dy="1.2em" class="st4">Jasper Reports<v:newlineChar/></tspan><tspan
x="-68.91" dy="1.2em" class="st4">Excel<v:newlineChar/></tspan><tspan x="-99.48" dy="1.2em" class="st4">Spring Portlet MVC</tspan></text> </g>
</g>
<g id="group21-72" transform="translate(269.291,-481.89) scale(-1,1)" v:mID="21" v:groupContext="group">
<v:userDefs>
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<title>3-D box.21</title>
<desc>ORM Hibernate JPA TopLink JDO OJB iBatis</desc>
<g id="shape22-73" v:mID="22" v:groupContext="shape" transform="translate(0,14.1732)">
<title>Sheet.22</title>
<path d="M0 827.72 L107.72 827.72 L93.54 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
</g>
<g id="shape23-75" v:mID="23" v:groupContext="shape" transform="translate(-14.1732,0)">
<title>Sheet.23</title>
<path d="M0 856.06 L14.17 841.89 L14.17 657.64 L0 671.81 L0 856.06 Z" class="st1"/>
</g>
<g id="shape24-77" v:mID="24" v:groupContext="shape">
<title>Sheet.24</title>
<rect x="0" y="657.638" width="107.717" height="184.252" class="st2"/>
</g>
<g id="shape21-79" v:mID="21" v:groupContext="groupContent">
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
<v:textRect cx="53.8583" cy="749.764" width="107.72" height="184.252"/>
<text x="-88.86" y="717.96" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>ORM<v:newlineChar/><v:newlineChar/><tspan
x="-75.55" dy="2.76em" class="st4">Hibernate<v:newlineChar/></tspan><tspan x="-63.04" dy="1.2em"
class="st4">JPA<v:newlineChar/></tspan><tspan x="-71.65" dy="1.2em" class="st4">TopLink<v:newlineChar/></tspan><tspan
x="-63.87" dy="1.2em" class="st4">JDO<v:newlineChar/></tspan><tspan x="-63.59" dy="1.2em" class="st4">OJB<v:newlineChar/></tspan><tspan
x="-66.09" dy="1.2em" class="st4">iBatis</tspan></text> </g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 thirdparty-web.svg Page-1 -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="4.90667in"
height="3.29238in" viewBox="0 0 353.28 237.051" xml:space="preserve" color-interpolation-filters="sRGB" class="st9">
<v:documentProperties v:langID="1033" v:viewMarkup="false"/>
<style type="text/css">
<![CDATA[
.st1 {fill:#f4f7f0;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st2 {fill:#000000;font-family:Arial;font-size:0.833336em}
.st3 {fill:#ecefe2;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st4 {visibility:visible}
.st5 {fill:#84877b;stroke:#84877b;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st6 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st7 {fill:#000000;font-family:Arial;font-size:0.75em}
.st8 {font-size:1em}
.st9 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
<title>Page-1</title>
<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
<g id="shape11-1" v:mID="11" v:groupContext="shape" transform="translate(0.24,-0.24)">
<title>Box.11</title>
<desc>Servlet Container (Tomcat / Jetty)</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="176.4" cy="118.766" width="352.8" height="236.571"/>
<rect x="0" y="0.48" width="352.8" height="236.571" class="st1"/>
<text x="101.65" y="223.77" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Servlet Container (Tomcat / Jetty)</text> </g>
<g id="shape6-4" v:mID="6" v:groupContext="shape" transform="translate(12.84,-25.9543)">
<title>Box.6</title>
<desc>Spring Core</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="81.9" cy="206.194" width="163.8" height="61.7143"/>
<rect x="0" y="175.337" width="163.8" height="61.7143" class="st3"/>
<text x="55.22" y="221.19" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring Core</text> </g>
<g id="shape7-7" v:mID="7" v:groupContext="shape" transform="translate(176.64,-25.9543)">
<title>Box.7</title>
<desc>Spring DAO</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="81.9" cy="206.194" width="163.81" height="61.7143"/>
<rect x="0" y="175.337" width="163.8" height="61.7143" class="st3"/>
<text x="55.22" y="221.19" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring DAO</text> </g>
<g id="shape8-10" v:mID="8" v:groupContext="shape" transform="translate(176.64,-87.6686)">
<title>Box.8</title>
<desc>Spring ORM</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="81.9" cy="206.194" width="163.8" height="61.7143"/>
<rect x="0" y="175.337" width="163.8" height="61.7143" class="st3"/>
<text x="54.39" y="197.19" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring ORM<v:newlineChar/><v:newlineChar/></text> </g>
<g id="shape9-13" v:mID="9" v:groupContext="shape" transform="translate(12.84,-149.383)">
<title>Box.9</title>
<desc>Spring WEB</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="163.8" cy="206.194" width="327.6" height="61.7143"/>
<rect x="0" y="175.337" width="327.6" height="61.7143" class="st3"/>
<text x="136.57" y="221.19" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring WEB</text> </g>
<g id="shape10-16" v:mID="10" v:groupContext="shape" transform="translate(107.34,-188.811)">
<title>Box.10</title>
<desc>Web frontend using Struts or WebWork</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="72.45" cy="218.194" width="144.91" height="37.7143"/>
<g id="shadow10-17" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="199.337" width="144.9" height="37.7143" class="st5"/>
</g>
<rect x="0" y="199.337" width="144.9" height="37.7143" class="st6"/>
<text x="33.43" y="215.49" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Web frontend using<v:newlineChar/><tspan
x="34.44" dy="1.2em" class="st8">Struts or WebWork</tspan></text> </g>
<g id="shape12-22" v:mID="12" v:groupContext="shape" transform="translate(12.84,-87.6686)">
<title>Box.12</title>
<desc>Spring AOP</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="81.9" cy="206.194" width="163.8" height="61.7143"/>
<rect x="0" y="175.337" width="163.8" height="61.7143" class="st3"/>
<text x="55.5" y="197.19" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring AOP<v:newlineChar/><v:newlineChar/></text> </g>
<g id="shape13-25" v:mID="13" v:groupContext="shape" transform="translate(107.34,-94.5257)">
<title>Box.13</title>
<desc>Transaction management Using Spring decl. trans.</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="72.45" cy="223.337" width="144.91" height="27.4286"/>
<g id="shadow13-26" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="209.623" width="144.9" height="27.4286" class="st5"/>
</g>
<rect x="0" y="209.623" width="144.9" height="27.4286" class="st6"/>
<text x="21.42" y="220.64" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Transaction management<v:newlineChar/><tspan
x="23.43" dy="1.2em" class="st8">Using Spring decl</tspan>. trans.</text> </g>
<g id="shape5-31" v:mID="5" v:groupContext="shape" transform="translate(107.34,-67.0971)">
<title>Box</title>
<desc>Hibernate mappings Custom Hibernate DAOs</desc>
<v:userDefs>
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
</v:userDefs>
<v:textBlock v:margins="rect(4,4,4,4)"/>
<v:textRect cx="72.45" cy="223.337" width="144.91" height="27.4286"/>
<g id="shadow5-32" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
<rect x="0" y="209.623" width="144.9" height="27.4286" class="st5"/>
</g>
<rect x="0" y="209.623" width="144.9" height="27.4286" class="st6"/>
<text x="32.18" y="220.64" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hibernate mappings<v:newlineChar/><tspan
x="22.93" dy="1.2em" class="st8">Custom Hibernate DAOs</tspan></text> </g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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>

View File

@ -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>&lt;!--
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:
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
-->
&lt;!--
The document root. A document can contain bean definitions only,
imports only, or a mixture of both (typically with imports first).
-->
&lt;!ELEMENT beans (
description?,
(import | alias | bean)*
)>
&lt;!--
Default values for all bean definitions. Can be overridden at
the "bean" level. See those attribute definitions for details.
-->
&lt;!ATTLIST beans default-lazy-init (true | false) "false">
&lt;!ATTLIST beans default-autowire (no | byName | byType | constructor | autodetect) "no">
&lt;!ATTLIST beans default-dependency-check (none | objects | simple | all) "none">
&lt;!ATTLIST beans default-init-method CDATA #IMPLIED>
&lt;!ATTLIST beans default-destroy-method CDATA #IMPLIED>
&lt;!ATTLIST beans default-merge (true | false) "false">
&lt;!--
Element containing informative text describing the purpose of the enclosing
element. Always optional.
Used primarily for user documentation of XML bean definition documents.
-->
&lt;!ELEMENT description (#PCDATA)>
&lt;!--
Specifies an XML bean definition resource to import.
-->
&lt;!ELEMENT import EMPTY>
&lt;!--
The relative resource location of the XML bean definition file to import,
for example "myImport.xml" or "includes/myImport.xml" or "../myImport.xml".
-->
&lt;!ATTLIST import resource CDATA #REQUIRED>
&lt;!--
Defines an alias for a bean, which can reside in a different definition file.
-->
&lt;!ELEMENT alias EMPTY>
&lt;!--
The name of the bean to define an alias for.
-->
&lt;!ATTLIST alias name CDATA #REQUIRED>
&lt;!--
The alias name to define for the bean.
-->
&lt;!ATTLIST alias alias CDATA #REQUIRED>
&lt;!--
Allows for arbitrary metadata to be attached to a bean definition.
-->
&lt;!ELEMENT meta EMPTY>
&lt;!--
Specifies the key name of the metadata parameter being defined.
-->
&lt;!ATTLIST meta key CDATA #REQUIRED>
&lt;!--
Specifies the value of the metadata parameter being defined as a String.
-->
&lt;!ATTLIST meta value CDATA #REQUIRED>
&lt;!--
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.
-->
&lt;!ELEMENT bean (
description?,
(meta | constructor-arg | property | lookup-method | replaced-method)*
)>
&lt;!--
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).
-->
&lt;!ATTLIST bean id ID #IMPLIED>
&lt;!--
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).
-->
&lt;!ATTLIST bean name CDATA #IMPLIED>
&lt;!--
Each bean definition must specify the fully qualified name of the class,
except if it pure serves as parent for child bean definitions.
-->
&lt;!ATTLIST bean class CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST bean parent CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST bean scope CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST bean abstract (true | false) #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST bean lazy-init (true | false | default) "default">
&lt;!--
Indicates whether or not this bean should be considered when looking
for candidates to satisfy another beans autowiring requirements.
-->
&lt;!ATTLIST bean autowire-candidate (true | false) #IMPLIED>
&lt;!--
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 &lt;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.
-->
&lt;!ATTLIST bean autowire (no | byName | byType | constructor | autodetect | default) "default">
&lt;!--
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.
-->
&lt;!ATTLIST bean dependency-check (none | objects | simple | all | default) "default">
&lt;!--
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.
-->
&lt;!ATTLIST bean depends-on CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST bean init-method CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST bean destroy-method CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST bean factory-method CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST bean factory-bean CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ELEMENT constructor-arg (
description?,
(bean | ref | idref | value | null | list | set | map | props)?
)>
&lt;!--
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.
-->
&lt;!ATTLIST constructor-arg index CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST constructor-arg type CDATA #IMPLIED>
&lt;!--
A short-cut alternative to a child element "ref bean=".
-->
&lt;!ATTLIST constructor-arg ref CDATA #IMPLIED>
&lt;!--
A short-cut alternative to a child element "value".
-->
&lt;!ATTLIST constructor-arg value CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ELEMENT property (
description?, meta*,
(bean | ref | idref | value | null | list | set | map | props)?
)>
&lt;!--
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.
-->
&lt;!ATTLIST property name CDATA #REQUIRED>
&lt;!--
A short-cut alternative to a child element "ref bean=".
-->
&lt;!ATTLIST property ref CDATA #IMPLIED>
&lt;!--
A short-cut alternative to a child element "value".
-->
&lt;!ATTLIST property value CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ELEMENT lookup-method EMPTY>
&lt;!--
Name of a lookup method. This method should take no arguments.
-->
&lt;!ATTLIST lookup-method name CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST lookup-method bean CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ELEMENT replaced-method (
(arg-type)*
)>
&lt;!--
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.
-->
&lt;!ATTLIST replaced-method name CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ATTLIST replaced-method replacer CDATA #IMPLIED>
&lt;!--
Subelement of replaced-method identifying an argument for a replaced method
in the event of method overloading.
-->
&lt;!ELEMENT arg-type (#PCDATA)>
&lt;!--
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.
-->
&lt;!ATTLIST arg-type match CDATA #IMPLIED>
&lt;!--
Defines a reference to another bean in this factory or an external
factory (parent or included factory).
-->
&lt;!ELEMENT ref EMPTY>
&lt;!--
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.
-->
&lt;!ATTLIST ref bean CDATA #IMPLIED>
&lt;!ATTLIST ref local IDREF #IMPLIED>
&lt;!ATTLIST ref parent CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ELEMENT idref EMPTY>
&lt;!--
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.
-->
&lt;!ATTLIST idref bean CDATA #IMPLIED>
&lt;!ATTLIST idref local IDREF #IMPLIED>
&lt;!--
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.
-->
&lt;!ELEMENT value (#PCDATA)>
&lt;!--
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.
-->
&lt;!ATTLIST value type CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ELEMENT null (#PCDATA)>
&lt;!--
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.
-->
&lt;!ELEMENT list (
(bean | ref | idref | value | null | list | set | map | props)*
)>
&lt;!--
Enable/disable merging for collections when using parent/child beans.
-->
&lt;!ATTLIST list merge (true | false | default) "default">
&lt;!--
Specify the default Java type for nested values.
-->
&lt;!ATTLIST list value-type CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ELEMENT set (
(bean | ref | idref | value | null | list | set | map | props)*
)>
&lt;!--
Enable/disable merging for collections when using parent/child beans.
-->
&lt;!ATTLIST set merge (true | false | default) "default">
&lt;!--
Specify the default Java type for nested values.
-->
&lt;!ATTLIST set value-type CDATA #IMPLIED>
&lt;!--
A Spring map is a mapping from a string key to object.
Maps may be empty.
-->
&lt;!ELEMENT map (
(entry)*
)>
&lt;!--
Enable/disable merging for collections when using parent/child beans.
-->
&lt;!ATTLIST map merge (true | false | default) "default">
&lt;!--
Specify the default Java type for nested entry keys.
-->
&lt;!ATTLIST map key-type CDATA #IMPLIED>
&lt;!--
Specify the default Java type for nested entry values.
-->
&lt;!ATTLIST map value-type CDATA #IMPLIED>
&lt;!--
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.
-->
&lt;!ELEMENT entry (
key?,
(bean | ref | idref | value | null | list | set | map | props)?
)>
&lt;!--
Each map element must specify its key as attribute or as child element.
A key attribute is always a String value.
-->
&lt;!ATTLIST entry key CDATA #IMPLIED>
&lt;!--
A short-cut alternative to a "key" element with a "ref bean=" child element.
-->
&lt;!ATTLIST entry key-ref CDATA #IMPLIED>
&lt;!--
A short-cut alternative to a child element "value".
-->
&lt;!ATTLIST entry value CDATA #IMPLIED>
&lt;!--
A short-cut alternative to a child element "ref bean=".
-->
&lt;!ATTLIST entry value-ref CDATA #IMPLIED>
&lt;!--
A key element can contain an inner bean, ref, value, or collection.
-->
&lt;!ELEMENT key (
(bean | ref | idref | value | null | list | set | map | props)
)>
&lt;!--
Props elements differ from map elements in that values must be strings.
Props may be empty.
-->
&lt;!ELEMENT props (
(prop)*
)>
&lt;!--
Enable/disable merging for collections when using parent/child beans.
-->
&lt;!ATTLIST props merge (true | false | default) "default">
&lt;!--
Element content is the string value of the property.
Note that whitespace is trimmed off to avoid unwanted whitespace
caused by typical XML formatting.
-->
&lt;!ELEMENT prop (#PCDATA)>
&lt;!--
Each property element must specify its key.
-->
&lt;!ATTLIST prop key CDATA #REQUIRED></programlisting></para>
</appendix>

File diff suppressed because it is too large Load Diff

View File

@ -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. Well follow best practice and use the EJB Business Methods
Interface pattern, so that the EJBs local interface extends a non
EJB-specific business methods interface. Lets 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 well 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 well 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>
Theres a lot of work happening behind the scenes, courtesy of
the Spring AOP framework, although you arent 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 theres
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>&lt;jee:local-slsb&gt;</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 havent 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 dont want to make fine-grained calls
to EJBs anyway, as theres 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>&lt;jee:remote-slsb&gt;</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>&lt;jee:local-slsb&gt;</literal> and <literal>&lt;jee:remote-slsb&gt;</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>&lt;jee:jndi-lookup&gt;</literal>
as well, since fully usable component references are exposed for plain
JNDI lookups there. Defining explicit <literal>&lt;jee:local-slsb&gt;</literal>
/ <literal>&lt;jee:remote-slsb&gt;</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>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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>&lt;!-- this is a template message that we can pre-load with default state --&gt;</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>

View File

@ -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>&lt;!-- whoops, no MovieFinder is set (and this property is <interfacename>@Required</interfacename>) --&gt;</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>

File diff suppressed because it is too large Load Diff

View File

@ -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>&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd"&gt;</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>

View File

@ -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>

File diff suppressed because it is too large Load Diff

View File

@ -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>

File diff suppressed because it is too large Load Diff

View File

@ -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>

File diff suppressed because it is too large Load Diff

View File

@ -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("&lt;someFileInsideTheJar&gt;")</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>

View File

@ -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>&lt;!-- wait 10 seconds before starting repeated execution --&gt;</lineannotation><![CDATA[
<property name="delay" value="10000" />
]]><lineannotation>&lt;!-- run every 50 seconds --&gt;</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>&lt;!-- see the example above --&gt;</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>

File diff suppressed because it is too large Load Diff

View File

@ -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>

View File

@ -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>

View File

@ -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>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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>&lt;spring:bind/&gt;</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>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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>&lt;!-- myns.xsd (inside package org/springframework/samples/xml) --&gt;</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>&lt;myns:dateformat/&gt;</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>&lt;myns:dateformat/&gt;</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>&lt;dateformat/&gt;</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>&lt;!-- as a top-level bean --&gt;</lineannotation><![CDATA[
<myns:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm" lenient="true"/>
<bean id="jobDetailTemplate" abstract="true">
<property name="dateFormat">
]]><lineannotation>&lt;!-- as an inner bean --&gt;</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>&lt;foo:component/&gt;</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"&gt;</emphasis></lineannotation><![CDATA[
]]><lineannotation>&lt;!-- other dependencies here... --&gt;</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>

File diff suppressed because it is too large Load Diff

View File

@ -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.&#160;%t"/>
<l:template name="section" text="%n&#160;%t"/>
</l:context>
</l:l10n>
</l:i18n>
</xsl:stylesheet>

View File

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

View File

@ -0,0 +1,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.&#160;%t"/>
<l:template name="section" text="%n&#160;%t"/>
</l:context>
<l:context name="title">
<l:template name="example" text="Example&#160;%n&#160;%t"/>
</l:context>
</l:l10n>
</l:i18n>
</xsl:stylesheet>

View File

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