Added the Spring Framework reference documentation
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="spring-framework-reference" default="doc">
|
||||
|
||||
<property name="doc.type" value="reference"/>
|
||||
<property name="docbook.build.dir" value="${basedir}"/>
|
||||
<property file="${basedir}/../build.properties"/>
|
||||
<import file="${basedir}/../spring-build/docbook/default.xml"/>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
html {
|
||||
padding: 0pt;
|
||||
margin: 0pt;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-left: 10%;
|
||||
margin-right: 10%;
|
||||
font-family: Arial, Sans-serif;
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 0pt;
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid gray;
|
||||
background: gray;
|
||||
}
|
||||
|
||||
h1,h2,h3 {
|
||||
color: #234623;
|
||||
font-family: Arial, Sans-serif;
|
||||
}
|
||||
|
||||
pre {
|
||||
line-height: 1.0;
|
||||
color: black;
|
||||
}
|
||||
|
||||
pre.programlisting {
|
||||
font-size: 10pt;
|
||||
padding: 7pt 3pt;
|
||||
border: 1pt solid black;
|
||||
background: #eeeeee;
|
||||
}
|
||||
|
||||
div.table {
|
||||
margin: 1em;
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.table table {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.table td {
|
||||
padding-left: 7px;
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
|
@ -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 |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
|
@ -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 |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -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 |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
|
@ -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 |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
|
@ -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 |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
|
@ -0,0 +1,125 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<chapter id="dao">
|
||||
<title>DAO support</title>
|
||||
<section id="dao-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
The Data Access Object (DAO) support in Spring is aimed at
|
||||
making it easy to work with data access technologies like
|
||||
JDBC, Hibernate or JDO in a consistent way. This allows one
|
||||
to switch between the aforementioned persistence technologies
|
||||
fairly easily and it also allows one to code without worrying
|
||||
about catching exceptions that are specific to each technology.
|
||||
</para>
|
||||
</section>
|
||||
<section id="dao-exceptions">
|
||||
<title>Consistent exception hierarchy</title>
|
||||
<para>
|
||||
Spring provides a convenient translation from technology-specific
|
||||
exceptions like <classname>SQLException</classname> to its own
|
||||
exception class hierarchy with the
|
||||
<classname>DataAccessException</classname> as the root exception.
|
||||
These exceptions wrap the original exception so there is never
|
||||
any risk that one might lose any information as to what might
|
||||
have gone wrong.
|
||||
</para>
|
||||
<para>
|
||||
In addition to JDBC exceptions, Spring can also wrap Hibernate-specific
|
||||
exceptions, converting them from proprietary, checked exceptions
|
||||
(in the case of versions of Hibernate prior to Hibernate 3.0), to
|
||||
a set of focused runtime exceptions (the same is true for JDO and
|
||||
JPA exceptions). This allows one to handle most persistence exceptions,
|
||||
which are non-recoverable, only in the appropriate layers, without
|
||||
having annoying boilerplate catch-and-throw blocks and exception
|
||||
declarations in one's DAOs. (One can still trap and handle exceptions
|
||||
anywhere one needs to though.) As mentioned above, JDBC exceptions
|
||||
(including database-specific dialects) are also converted to the
|
||||
same hierarchy, meaning that one can perform some operations with
|
||||
JDBC within a consistent programming model.
|
||||
</para>
|
||||
<para>
|
||||
The above holds true for the various template classes in Springs
|
||||
support for various ORM frameworks. If one uses the interceptor-based
|
||||
classes then the application must care about handling
|
||||
<classname>HibernateExceptions</classname> and
|
||||
<classname>JDOExceptions</classname> itself, preferably via delegating
|
||||
to <classname>SessionFactoryUtils</classname>'
|
||||
<methodname>convertHibernateAccessException(..)</methodname> or
|
||||
<methodname>convertJdoAccessException</methodname> methods respectively.
|
||||
These methods convert the exceptions to ones that are compatible
|
||||
with the exceptions in the <literal>org.springframework.dao</literal>
|
||||
exception hierarchy. As <classname>JDOExceptions</classname> are
|
||||
unchecked, they can simply get thrown too, sacrificing generic DAO
|
||||
abstraction in terms of exceptions though.
|
||||
</para>
|
||||
<para>
|
||||
The exception hierarchy that Spring provides can be seen below.
|
||||
(Please note that the class hierarchy detailed in the image
|
||||
shows only a subset of the entire
|
||||
<classname>DataAccessException</classname> hierarchy.)
|
||||
</para>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="images/DataAccessException.gif" align="center" />
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</section>
|
||||
<section id="dao-abstract-superclasses">
|
||||
<title>Consistent abstract classes for DAO support</title>
|
||||
<para>
|
||||
To make it easier to work with a variety of data access technologies
|
||||
such as JDBC, JDO and Hibernate in a consistent way, Spring provides
|
||||
a set of <literal>abstract</literal> DAO classes that one can extend.
|
||||
These abstract classes have methods for providing the data source and
|
||||
any other configuration settings that are specific to the relevant
|
||||
data-access technology.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>JdbcDaoSupport</classname> - superclass for JDBC data
|
||||
access objects. Requires a <interfacename>DataSource</interfacename>
|
||||
to be provided; in turn, this class provides a
|
||||
<classname>JdbcTemplate</classname> instance initialized from the
|
||||
supplied <interfacename>DataSource</interfacename> to subclasses.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>HibernateDaoSupport</classname> - superclass for
|
||||
Hibernate data access objects. Requires a
|
||||
<interfacename>SessionFactory</interfacename> to be provided;
|
||||
in turn, this class provides a
|
||||
<classname>HibernateTemplate</classname> instance initialized
|
||||
from the supplied <interfacename>SessionFactory</interfacename>
|
||||
to subclasses. Can alternatively be initialized directly via a
|
||||
<classname>HibernateTemplate</classname>, to reuse the latters
|
||||
settings like <interfacename>SessionFactory</interfacename>,
|
||||
flush mode, exception translator, and so forth.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>JdoDaoSupport</classname> - super class for JDO data
|
||||
access objects. Requires a
|
||||
<interfacename>PersistenceManagerFactory</interfacename>
|
||||
to be provided; in turn, this class provides a
|
||||
<classname>JdoTemplate</classname> instance initialized from the
|
||||
supplied <interfacename>PersistenceManagerFactory</interfacename>
|
||||
to subclasses.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>JpaDaoSupport</classname> - super class for JPA data
|
||||
access objects. Requires a
|
||||
<interfacename>EntityManagerFactory</interfacename> to be provided;
|
||||
in turn, this class provides a <classname>JpaTemplate</classname>
|
||||
instance initialized from the supplied
|
||||
<interfacename>EntityManagerFactory</interfacename> to subclasses.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,681 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix id="springbeansdtd">
|
||||
<title><literal>spring-beans-2.0.dtd</literal></title>
|
||||
|
||||
<para><programlisting><!--
|
||||
Spring XML Beans DTD, version 2.0
|
||||
Authors: Rod Johnson, Juergen Hoeller, Alef Arendsen, Colin Sampaleanu, Rob Harrop
|
||||
|
||||
This defines a simple and consistent way of creating a namespace
|
||||
of JavaBeans objects, managed by a Spring BeanFactory, read by
|
||||
XmlBeanDefinitionReader (with DefaultBeanDefinitionDocumentReader).
|
||||
|
||||
This document type is used by most Spring functionality, including
|
||||
web application contexts, which are based on bean factories.
|
||||
|
||||
Each "bean" element in this document defines a JavaBean.
|
||||
Typically the bean class is specified, along with JavaBean properties
|
||||
and/or constructor arguments.
|
||||
|
||||
A bean instance can be a "singleton" (shared instance) or a "prototype"
|
||||
(independent instance). Further scopes can be provided by extended
|
||||
bean factories, for example in a web environment.
|
||||
|
||||
References among beans are supported, that is, setting a JavaBean property
|
||||
or a constructor argument to refer to another bean in the same factory
|
||||
(or an ancestor factory).
|
||||
|
||||
As alternative to bean references, "inner bean definitions" can be used.
|
||||
Singleton flags of such inner bean definitions are effectively ignored:
|
||||
Inner beans are typically anonymous prototypes.
|
||||
|
||||
There is also support for lists, sets, maps, and java.util.Properties
|
||||
as bean property types or constructor argument types.
|
||||
|
||||
For simple purposes, this DTD is sufficient. As of Spring 2.0,
|
||||
XSD-based bean definitions are supported as more powerful alternative.
|
||||
|
||||
XML documents that conform to this DTD should declare the following doctype:
|
||||
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
|
||||
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
The document root. A document can contain bean definitions only,
|
||||
imports only, or a mixture of both (typically with imports first).
|
||||
-->
|
||||
<!ELEMENT beans (
|
||||
description?,
|
||||
(import | alias | bean)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Default values for all bean definitions. Can be overridden at
|
||||
the "bean" level. See those attribute definitions for details.
|
||||
-->
|
||||
<!ATTLIST beans default-lazy-init (true | false) "false">
|
||||
<!ATTLIST beans default-autowire (no | byName | byType | constructor | autodetect) "no">
|
||||
<!ATTLIST beans default-dependency-check (none | objects | simple | all) "none">
|
||||
<!ATTLIST beans default-init-method CDATA #IMPLIED>
|
||||
<!ATTLIST beans default-destroy-method CDATA #IMPLIED>
|
||||
<!ATTLIST beans default-merge (true | false) "false">
|
||||
|
||||
<!--
|
||||
Element containing informative text describing the purpose of the enclosing
|
||||
element. Always optional.
|
||||
Used primarily for user documentation of XML bean definition documents.
|
||||
-->
|
||||
<!ELEMENT description (#PCDATA)>
|
||||
|
||||
|
||||
<!--
|
||||
Specifies an XML bean definition resource to import.
|
||||
-->
|
||||
<!ELEMENT import EMPTY>
|
||||
|
||||
<!--
|
||||
The relative resource location of the XML bean definition file to import,
|
||||
for example "myImport.xml" or "includes/myImport.xml" or "../myImport.xml".
|
||||
-->
|
||||
<!ATTLIST import resource CDATA #REQUIRED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines an alias for a bean, which can reside in a different definition file.
|
||||
-->
|
||||
<!ELEMENT alias EMPTY>
|
||||
|
||||
<!--
|
||||
The name of the bean to define an alias for.
|
||||
-->
|
||||
<!ATTLIST alias name CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
The alias name to define for the bean.
|
||||
-->
|
||||
<!ATTLIST alias alias CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
Allows for arbitrary metadata to be attached to a bean definition.
|
||||
-->
|
||||
<!ELEMENT meta EMPTY>
|
||||
|
||||
<!--
|
||||
Specifies the key name of the metadata parameter being defined.
|
||||
-->
|
||||
<!ATTLIST meta key CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
Specifies the value of the metadata parameter being defined as a String.
|
||||
-->
|
||||
<!ATTLIST meta value CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
Defines a single (usually named) bean.
|
||||
|
||||
A bean definition may contain nested tags for constructor arguments,
|
||||
property values, lookup methods, and replaced methods. Mixing constructor
|
||||
injection and setter injection on the same bean is explicitly supported.
|
||||
-->
|
||||
<!ELEMENT bean (
|
||||
description?,
|
||||
(meta | constructor-arg | property | lookup-method | replaced-method)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Beans can be identified by an id, to enable reference checking.
|
||||
|
||||
There are constraints on a valid XML id: if you want to reference your bean
|
||||
in Java code using a name that's illegal as an XML id, use the optional
|
||||
"name" attribute. If neither is given, the bean class name is used as id
|
||||
(with an appended counter like "#2" if there is already a bean with that name).
|
||||
-->
|
||||
<!ATTLIST bean id ID #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional. Can be used to create one or more aliases illegal in an id.
|
||||
Multiple aliases can be separated by any number of spaces, commas, or
|
||||
semi-colons (or indeed any mixture of the three).
|
||||
-->
|
||||
<!ATTLIST bean name CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Each bean definition must specify the fully qualified name of the class,
|
||||
except if it pure serves as parent for child bean definitions.
|
||||
-->
|
||||
<!ATTLIST bean class CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optionally specify a parent bean definition.
|
||||
|
||||
Will use the bean class of the parent if none specified, but can
|
||||
also override it. In the latter case, the child bean class must be
|
||||
compatible with the parent, i.e. accept the parent's property values
|
||||
and constructor argument values, if any.
|
||||
|
||||
A child bean definition will inherit constructor argument values,
|
||||
property values and method overrides from the parent, with the option
|
||||
to add new values. If init method, destroy method, factory bean and/or factory
|
||||
method are specified, they will override the corresponding parent settings.
|
||||
|
||||
The remaining settings will always be taken from the child definition:
|
||||
depends on, autowire mode, dependency check, scope, lazy init.
|
||||
-->
|
||||
<!ATTLIST bean parent CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
The scope of this bean: typically "singleton" (one shared instance,
|
||||
which will be returned by all calls to getBean() with the id),
|
||||
or "prototype" (independent instance resulting from each call to
|
||||
getBean(). Default is "singleton".
|
||||
|
||||
Singletons are most commonly used, and are ideal for multi-threaded
|
||||
service objects. Further scopes, such as "request" or "session",
|
||||
might be supported by extended bean factories (for example, in a
|
||||
web environment).
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
|
||||
Inner bean definitions inherit the singleton status of their containing
|
||||
bean definition, unless explicitly specified: The inner bean will be a
|
||||
singleton if the containing bean is a singleton, and a prototype if
|
||||
the containing bean has any other scope.
|
||||
-->
|
||||
<!ATTLIST bean scope CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Is this bean "abstract", i.e. not meant to be instantiated itself but
|
||||
rather just serving as parent for concrete child bean definitions.
|
||||
Default is "false". Specify "true" to tell the bean factory to not try to
|
||||
instantiate that particular bean in any case.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per abstract bean definition.
|
||||
-->
|
||||
<!ATTLIST bean abstract (true | false) #IMPLIED>
|
||||
|
||||
<!--
|
||||
If this bean should be lazily initialized.
|
||||
If false, it will get instantiated on startup by bean factories
|
||||
that perform eager initialization of singletons.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean lazy-init (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Indicates whether or not this bean should be considered when looking
|
||||
for candidates to satisfy another beans autowiring requirements.
|
||||
-->
|
||||
<!ATTLIST bean autowire-candidate (true | false) #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute controlling whether to "autowire" bean properties.
|
||||
This is an automagical process in which bean references don't need to be coded
|
||||
explicitly in the XML bean definition file, but Spring works out dependencies.
|
||||
|
||||
There are 5 modes:
|
||||
|
||||
1. "no"
|
||||
The traditional Spring default. No automagical wiring. Bean references
|
||||
must be defined in the XML file via the <ref> element. We recommend this
|
||||
in most cases as it makes documentation more explicit.
|
||||
|
||||
2. "byName"
|
||||
Autowiring by property name. If a bean of class Cat exposes a dog property,
|
||||
Spring will try to set this to the value of the bean "dog" in the current factory.
|
||||
If there is no matching bean by name, nothing special happens;
|
||||
use dependency-check="objects" to raise an error in that case.
|
||||
|
||||
3. "byType"
|
||||
Autowiring if there is exactly one bean of the property type in the bean factory.
|
||||
If there is more than one, a fatal error is raised, and you can't use byType
|
||||
autowiring for that bean. If there is none, nothing special happens;
|
||||
use dependency-check="objects" to raise an error in that case.
|
||||
|
||||
4. "constructor"
|
||||
Analogous to "byType" for constructor arguments. If there isn't exactly one bean
|
||||
of the constructor argument type in the bean factory, a fatal error is raised.
|
||||
|
||||
5. "autodetect"
|
||||
Chooses "constructor" or "byType" through introspection of the bean class.
|
||||
If a default constructor is found, "byType" gets applied.
|
||||
|
||||
The latter two are similar to PicoContainer and make bean factories simple to
|
||||
configure for small namespaces, but doesn't work as well as standard Spring
|
||||
behaviour for bigger applications.
|
||||
|
||||
Note that explicit dependencies, i.e. "property" and "constructor-arg" elements,
|
||||
always override autowiring. Autowire behavior can be combined with dependency
|
||||
checking, which will be performed after all autowiring has been completed.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean autowire (no | byName | byType | constructor | autodetect | default) "default">
|
||||
|
||||
<!--
|
||||
Optional attribute controlling whether to check whether all this
|
||||
beans dependencies, expressed in its properties, are satisfied.
|
||||
Default is no dependency checking.
|
||||
|
||||
"simple" type dependency checking includes primitives and String;
|
||||
"objects" includes collaborators (other beans in the factory);
|
||||
"all" includes both types of dependency checking.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean dependency-check (none | objects | simple | all | default) "default">
|
||||
|
||||
<!--
|
||||
The names of the beans that this bean depends on being initialized.
|
||||
The bean factory will guarantee that these beans get initialized before.
|
||||
|
||||
Note that dependencies are normally expressed through bean properties or
|
||||
constructor arguments. This property should just be necessary for other kinds
|
||||
of dependencies like statics (*ugh*) or database preparation on startup.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean depends-on CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute for the name of the custom initialization method
|
||||
to invoke after setting bean properties. The method must have no arguments,
|
||||
but may throw any exception.
|
||||
-->
|
||||
<!ATTLIST bean init-method CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute for the name of the custom destroy method to invoke
|
||||
on bean factory shutdown. The method must have no arguments,
|
||||
but may throw any exception.
|
||||
|
||||
Note: Only invoked on beans whose lifecycle is under full control
|
||||
of the factory - which is always the case for singletons, but not
|
||||
guaranteed for any other scope.
|
||||
-->
|
||||
<!ATTLIST bean destroy-method CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute specifying the name of a factory method to use to
|
||||
create this object. Use constructor-arg elements to specify arguments
|
||||
to the factory method, if it takes arguments. Autowiring does not apply
|
||||
to factory methods.
|
||||
|
||||
If the "class" attribute is present, the factory method will be a static
|
||||
method on the class specified by the "class" attribute on this bean
|
||||
definition. Often this will be the same class as that of the constructed
|
||||
object - for example, when the factory method is used as an alternative
|
||||
to a constructor. However, it may be on a different class. In that case,
|
||||
the created object will *not* be of the class specified in the "class"
|
||||
attribute. This is analogous to FactoryBean behavior.
|
||||
|
||||
If the "factory-bean" attribute is present, the "class" attribute is not
|
||||
used, and the factory method will be an instance method on the object
|
||||
returned from a getBean call with the specified bean name. The factory
|
||||
bean may be defined as a singleton or a prototype.
|
||||
|
||||
The factory method can have any number of arguments. Autowiring is not
|
||||
supported. Use indexed constructor-arg elements in conjunction with the
|
||||
factory-method attribute.
|
||||
|
||||
Setter Injection can be used in conjunction with a factory method.
|
||||
Method Injection cannot, as the factory method returns an instance,
|
||||
which will be used when the container creates the bean.
|
||||
-->
|
||||
<!ATTLIST bean factory-method CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Alternative to class attribute for factory-method usage.
|
||||
If this is specified, no class attribute should be used.
|
||||
This should be set to the name of a bean in the current or
|
||||
ancestor factories that contains the relevant factory method.
|
||||
This allows the factory itself to be configured using Dependency
|
||||
Injection, and an instance (rather than static) method to be used.
|
||||
-->
|
||||
<!ATTLIST bean factory-bean CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Bean definitions can specify zero or more constructor arguments.
|
||||
This is an alternative to "autowire constructor".
|
||||
Arguments correspond to either a specific index of the constructor argument
|
||||
list or are supposed to be matched generically by type.
|
||||
|
||||
Note: A single generic argument value will just be used once, rather than
|
||||
potentially matched multiple times (as of Spring 1.1).
|
||||
|
||||
constructor-arg elements are also used in conjunction with the factory-method
|
||||
element to construct beans using static or instance factory methods.
|
||||
-->
|
||||
<!ELEMENT constructor-arg (
|
||||
description?,
|
||||
(bean | ref | idref | value | null | list | set | map | props)?
|
||||
)>
|
||||
|
||||
<!--
|
||||
The constructor-arg tag can have an optional index attribute,
|
||||
to specify the exact index in the constructor argument list. Only needed
|
||||
to avoid ambiguities, e.g. in case of 2 arguments of the same type.
|
||||
-->
|
||||
<!ATTLIST constructor-arg index CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
The constructor-arg tag can have an optional type attribute,
|
||||
to specify the exact type of the constructor argument. Only needed
|
||||
to avoid ambiguities, e.g. in case of 2 single argument constructors
|
||||
that can both be converted from a String.
|
||||
-->
|
||||
<!ATTLIST constructor-arg type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "ref bean=".
|
||||
-->
|
||||
<!ATTLIST constructor-arg ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "value".
|
||||
-->
|
||||
<!ATTLIST constructor-arg value CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Bean definitions can have zero or more properties.
|
||||
Property elements correspond to JavaBean setter methods exposed
|
||||
by the bean classes. Spring supports primitives, references to other
|
||||
beans in the same or related factories, lists, maps and properties.
|
||||
-->
|
||||
<!ELEMENT property (
|
||||
description?, meta*,
|
||||
(bean | ref | idref | value | null | list | set | map | props)?
|
||||
)>
|
||||
|
||||
<!--
|
||||
The property name attribute is the name of the JavaBean property.
|
||||
This follows JavaBean conventions: a name of "age" would correspond
|
||||
to setAge()/optional getAge() methods.
|
||||
-->
|
||||
<!ATTLIST property name CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "ref bean=".
|
||||
-->
|
||||
<!ATTLIST property ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "value".
|
||||
-->
|
||||
<!ATTLIST property value CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A lookup method causes the IoC container to override the given method and return
|
||||
the bean with the name given in the bean attribute. This is a form of Method Injection.
|
||||
It's particularly useful as an alternative to implementing the BeanFactoryAware
|
||||
interface, in order to be able to make getBean() calls for non-singleton instances
|
||||
at runtime. In this case, Method Injection is a less invasive alternative.
|
||||
-->
|
||||
<!ELEMENT lookup-method EMPTY>
|
||||
|
||||
<!--
|
||||
Name of a lookup method. This method should take no arguments.
|
||||
-->
|
||||
<!ATTLIST lookup-method name CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Name of the bean in the current or ancestor factories that the lookup method
|
||||
should resolve to. Often this bean will be a prototype, in which case the
|
||||
lookup method will return a distinct instance on every invocation. This
|
||||
is useful for single-threaded objects.
|
||||
-->
|
||||
<!ATTLIST lookup-method bean CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Similar to the lookup method mechanism, the replaced-method element is used to control
|
||||
IoC container method overriding: Method Injection. This mechanism allows the overriding
|
||||
of a method with arbitrary code.
|
||||
-->
|
||||
<!ELEMENT replaced-method (
|
||||
(arg-type)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Name of the method whose implementation should be replaced by the IoC container.
|
||||
If this method is not overloaded, there's no need to use arg-type subelements.
|
||||
If this method is overloaded, arg-type subelements must be used for all
|
||||
override definitions for the method.
|
||||
-->
|
||||
<!ATTLIST replaced-method name CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Bean name of an implementation of the MethodReplacer interface in the current
|
||||
or ancestor factories. This may be a singleton or prototype bean. If it's
|
||||
a prototype, a new instance will be used for each method replacement.
|
||||
Singleton usage is the norm.
|
||||
-->
|
||||
<!ATTLIST replaced-method replacer CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Subelement of replaced-method identifying an argument for a replaced method
|
||||
in the event of method overloading.
|
||||
-->
|
||||
<!ELEMENT arg-type (#PCDATA)>
|
||||
|
||||
<!--
|
||||
Specification of the type of an overloaded method argument as a String.
|
||||
For convenience, this may be a substring of the FQN. E.g. all the
|
||||
following would match "java.lang.String":
|
||||
- java.lang.String
|
||||
- String
|
||||
- Str
|
||||
|
||||
As the number of arguments will be checked also, this convenience can often
|
||||
be used to save typing.
|
||||
-->
|
||||
<!ATTLIST arg-type match CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines a reference to another bean in this factory or an external
|
||||
factory (parent or included factory).
|
||||
-->
|
||||
<!ELEMENT ref EMPTY>
|
||||
|
||||
<!--
|
||||
References must specify a name of the target bean.
|
||||
The "bean" attribute can reference any name from any bean in the context,
|
||||
to be checked at runtime.
|
||||
Local references, using the "local" attribute, have to use bean ids;
|
||||
they can be checked by this DTD, thus should be preferred for references
|
||||
within the same bean factory XML file.
|
||||
-->
|
||||
<!ATTLIST ref bean CDATA #IMPLIED>
|
||||
<!ATTLIST ref local IDREF #IMPLIED>
|
||||
<!ATTLIST ref parent CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines a string property value, which must also be the id of another
|
||||
bean in this factory or an external factory (parent or included factory).
|
||||
While a regular 'value' element could instead be used for the same effect,
|
||||
using idref in this case allows validation of local bean ids by the XML
|
||||
parser, and name completion by supporting tools.
|
||||
-->
|
||||
<!ELEMENT idref EMPTY>
|
||||
|
||||
<!--
|
||||
ID refs must specify a name of the target bean.
|
||||
The "bean" attribute can reference any name from any bean in the context,
|
||||
potentially to be checked at runtime by bean factory implementations.
|
||||
Local references, using the "local" attribute, have to use bean ids;
|
||||
they can be checked by this DTD, thus should be preferred for references
|
||||
within the same bean factory XML file.
|
||||
-->
|
||||
<!ATTLIST idref bean CDATA #IMPLIED>
|
||||
<!ATTLIST idref local IDREF #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Contains a string representation of a property value.
|
||||
The property may be a string, or may be converted to the required
|
||||
type using the JavaBeans PropertyEditor machinery. This makes it
|
||||
possible for application developers to write custom PropertyEditor
|
||||
implementations that can convert strings to arbitrary target objects.
|
||||
|
||||
Note that this is recommended for simple objects only.
|
||||
Configure more complex objects by populating JavaBean
|
||||
properties with references to other beans.
|
||||
-->
|
||||
<!ELEMENT value (#PCDATA)>
|
||||
|
||||
<!--
|
||||
The value tag can have an optional type attribute, to specify the
|
||||
exact type that the value should be converted to. Only needed
|
||||
if the type of the target property or constructor argument is
|
||||
too generic: for example, in case of a collection element.
|
||||
-->
|
||||
<!ATTLIST value type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Denotes a Java null value. Necessary because an empty "value" tag
|
||||
will resolve to an empty String, which will not be resolved to a
|
||||
null value unless a special PropertyEditor does so.
|
||||
-->
|
||||
<!ELEMENT null (#PCDATA)>
|
||||
|
||||
|
||||
<!--
|
||||
A list can contain multiple inner bean, ref, collection, or value elements.
|
||||
Java lists are untyped, pending generics support in Java 1.5,
|
||||
although references will be strongly typed.
|
||||
A list can also map to an array type. The necessary conversion
|
||||
is automatically performed by the BeanFactory.
|
||||
-->
|
||||
<!ELEMENT list (
|
||||
(bean | ref | idref | value | null | list | set | map | props)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST list merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested values.
|
||||
-->
|
||||
<!ATTLIST list value-type CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A set can contain multiple inner bean, ref, collection, or value elements.
|
||||
Java sets are untyped, pending generics support in Java 1.5,
|
||||
although references will be strongly typed.
|
||||
-->
|
||||
<!ELEMENT set (
|
||||
(bean | ref | idref | value | null | list | set | map | props)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST set merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested values.
|
||||
-->
|
||||
<!ATTLIST set value-type CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A Spring map is a mapping from a string key to object.
|
||||
Maps may be empty.
|
||||
-->
|
||||
<!ELEMENT map (
|
||||
(entry)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST map merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested entry keys.
|
||||
-->
|
||||
<!ATTLIST map key-type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested entry values.
|
||||
-->
|
||||
<!ATTLIST map value-type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A map entry can be an inner bean, ref, value, or collection.
|
||||
The key of the entry is given by the "key" attribute or child element.
|
||||
-->
|
||||
<!ELEMENT entry (
|
||||
key?,
|
||||
(bean | ref | idref | value | null | list | set | map | props)?
|
||||
)>
|
||||
|
||||
<!--
|
||||
Each map element must specify its key as attribute or as child element.
|
||||
A key attribute is always a String value.
|
||||
-->
|
||||
<!ATTLIST entry key CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a "key" element with a "ref bean=" child element.
|
||||
-->
|
||||
<!ATTLIST entry key-ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "value".
|
||||
-->
|
||||
<!ATTLIST entry value CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "ref bean=".
|
||||
-->
|
||||
<!ATTLIST entry value-ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A key element can contain an inner bean, ref, value, or collection.
|
||||
-->
|
||||
<!ELEMENT key (
|
||||
(bean | ref | idref | value | null | list | set | map | props)
|
||||
)>
|
||||
|
||||
|
||||
<!--
|
||||
Props elements differ from map elements in that values must be strings.
|
||||
Props may be empty.
|
||||
-->
|
||||
<!ELEMENT props (
|
||||
(prop)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST props merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Element content is the string value of the property.
|
||||
Note that whitespace is trimmed off to avoid unwanted whitespace
|
||||
caused by typical XML formatting.
|
||||
-->
|
||||
<!ELEMENT prop (#PCDATA)>
|
||||
|
||||
<!--
|
||||
Each property element must specify its key.
|
||||
-->
|
||||
<!ATTLIST prop key CDATA #REQUIRED></programlisting></para>
|
||||
</appendix>
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<chapter id="ejb">
|
||||
<title>Enterprise Java Beans (EJB) integration</title>
|
||||
|
||||
<section id="ejb-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
As a lightweight container, Spring is often considered an EJB
|
||||
replacement. We do believe that for many if not most applications and use
|
||||
cases, Spring as a container, combined with its rich supporting
|
||||
functionality in the area of transactions, ORM and JDBC access, is a better
|
||||
choice than implementing equivalent functionality via an EJB container and
|
||||
EJBs.
|
||||
</para>
|
||||
<para>
|
||||
However, it is important to note that using Spring does not prevent
|
||||
you from using EJBs. In fact, Spring makes it much easier to access EJBs and
|
||||
implement EJBs and functionality within them. Additionally, using Spring to
|
||||
access services provided by EJBs allows the implementation of those services
|
||||
to later transparently be switched between local EJB, remote EJB, or POJO
|
||||
(plain old Java object) variants, without the client code having to
|
||||
be changed.
|
||||
</para>
|
||||
<para>
|
||||
In this chapter, we look at how Spring can help you access and
|
||||
implement EJBs. Spring provides particular value when accessing stateless
|
||||
session beans (SLSBs), so we'll begin by discussing this.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access">
|
||||
<title>Accessing EJBs</title>
|
||||
|
||||
<section id="ejb-access-concepts">
|
||||
<title>Concepts</title>
|
||||
<para>
|
||||
To invoke a method on a local or remote stateless session bean,
|
||||
client code must normally perform a JNDI lookup to obtain the (local or
|
||||
remote) EJB Home object, then use a 'create' method call on that object
|
||||
to obtain the actual (local or remote) EJB object. One or more methods
|
||||
are then invoked on the EJB.
|
||||
</para>
|
||||
<para>
|
||||
To avoid repeated low-level code, many EJB applications use the
|
||||
Service Locator and Business Delegate patterns. These are better than
|
||||
spraying JNDI lookups throughout client code, but their usual
|
||||
implementations have significant disadvantages. For example:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Typically code using EJBs depends on Service Locator or
|
||||
Business Delegate singletons, making it hard to test.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
In the case of the Service Locator pattern used without a
|
||||
Business Delegate, application code still ends up having to invoke
|
||||
the create() method on an EJB home, and deal with the resulting
|
||||
exceptions. Thus it remains tied to the EJB API and the complexity
|
||||
of the EJB programming model.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Implementing the Business Delegate pattern typically results
|
||||
in significant code duplication, where we have to write numerous
|
||||
methods that simply call the same method on the EJB.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The Spring approach is to allow the creation and use of proxy objects,
|
||||
normally configured inside a Spring container, which act as codeless
|
||||
business delegates. You do not need to write another Service Locator, another
|
||||
JNDI lookup, or duplicate methods in a hand-coded Business Delegate unless
|
||||
you are actually adding real value in such code.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-local">
|
||||
<title>Accessing local SLSBs</title>
|
||||
<para>
|
||||
Assume that we have a web controller that needs to use a local
|
||||
EJB. We’ll follow best practice and use the EJB Business Methods
|
||||
Interface pattern, so that the EJB’s local interface extends a non
|
||||
EJB-specific business methods interface. Let’s call this business
|
||||
methods interface <classname>MyComponent</classname>.
|
||||
</para>
|
||||
<programlisting><![CDATA[public interface MyComponent {
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
One of the main reasons to use the Business Methods Interface pattern
|
||||
is to ensure that synchronization between method signatures in local
|
||||
interface and bean implementation class is automatic. Another reason is
|
||||
that it later makes it much easier for us to switch to a POJO (plain old
|
||||
Java object) implementation of the service if it makes sense to do so.
|
||||
Of course we’ll also need to implement the local home interface and
|
||||
provide an implementation class that implements <classname>SessionBean</classname>
|
||||
and the <classname>MyComponent</classname> business methods interface. Now the
|
||||
only Java coding we’ll need to do to hook up our web tier controller to the
|
||||
EJB implementation is to expose a setter method of type <classname>MyComponent</classname>
|
||||
on the controller. This will save the reference as an instance variable in the
|
||||
controller:
|
||||
</para>
|
||||
<programlisting><![CDATA[private MyComponent myComponent;
|
||||
|
||||
public void setMyComponent(MyComponent myComponent) {
|
||||
this.myComponent = myComponent;
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
We can subsequently use this instance variable in any business
|
||||
method in the controller. Now assuming we are obtaining our controller
|
||||
object out of a Spring container, we can (in the same context) configure a
|
||||
<classname>LocalStatelessSessionProxyFactoryBean</classname> instance, which
|
||||
will be the EJB proxy object. The configuration of the proxy, and setting of
|
||||
the <literal>myComponent</literal> property of the controller is done
|
||||
with a configuration entry such as:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean id="myComponent"
|
||||
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
|
||||
<property name="jndiName" value="ejb/myBean"/>
|
||||
<property name="businessInterface" value="com.mycom.MyComponent"/>
|
||||
</bean>
|
||||
|
||||
<bean id="myController" class="com.mycom.myController">
|
||||
<property name="myComponent" ref="myComponent"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
There’s a lot of work happening behind the scenes, courtesy of
|
||||
the Spring AOP framework, although you aren’t forced to work with AOP
|
||||
concepts to enjoy the results. The <literal>myComponent</literal> bean
|
||||
definition creates a proxy for the EJB, which implements the business
|
||||
method interface. The EJB local home is cached on startup, so there’s
|
||||
only a single JNDI lookup. Each time the EJB is invoked, the proxy
|
||||
invokes the <literal>classname</literal> method on the local EJB and
|
||||
invokes the corresponding business method on the EJB.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>myController</literal> bean definition sets the
|
||||
<literal>myComponent</literal> property of the controller class to the
|
||||
EJB proxy.
|
||||
</para>
|
||||
<para>
|
||||
Alternatively (and preferably in case of many such proxy definitions),
|
||||
consider using the <literal><jee:local-slsb></literal>
|
||||
configuration element in Spring's "jee" namespace:
|
||||
</para>
|
||||
<programlisting><![CDATA[<jee:local-slsb id="myComponent" jndi-name="ejb/myBean"
|
||||
business-interface="com.mycom.MyComponent"/>
|
||||
|
||||
<bean id="myController" class="com.mycom.myController">
|
||||
<property name="myComponent" ref="myComponent"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
This EJB access mechanism delivers huge simplification of
|
||||
application code: the web tier code (or other EJB client code) has no
|
||||
dependence on the use of EJB. If we want to replace this EJB reference
|
||||
with a POJO or a mock object or other test stub, we could simply change
|
||||
the <literal>myComponent</literal> bean definition without changing a
|
||||
line of Java code. Additionally, we haven’t had to write a single line of
|
||||
JNDI lookup or other EJB plumbing code as part of our application.
|
||||
</para>
|
||||
<para>
|
||||
Benchmarks and experience in real applications indicate that the
|
||||
performance overhead of this approach (which involves reflective
|
||||
invocation of the target EJB) is minimal, and is typically undetectable
|
||||
in typical use. Remember that we don’t want to make fine-grained calls
|
||||
to EJBs anyway, as there’s a cost associated with the EJB infrastructure
|
||||
in the application server.
|
||||
</para>
|
||||
<para>
|
||||
There is one caveat with regards to the JNDI lookup. In a bean
|
||||
container, this class is normally best used as a singleton (there simply
|
||||
is no reason to make it a prototype). However, if that bean container
|
||||
pre-instantiates singletons (as do the various XML
|
||||
<classname>ApplicationContext</classname> variants)
|
||||
you may have a problem if the bean container is loaded before the EJB
|
||||
container loads the target EJB. That is because the JNDI lookup will be
|
||||
performed in the <literal>init()</literal> method of this class and then
|
||||
cached, but the EJB will not have been bound at the target location yet.
|
||||
The solution is to not pre-instantiate this factory object, but allow it
|
||||
to be created on first use. In the XML containers, this is controlled via
|
||||
the <literal>lazy-init</literal> attribute.
|
||||
</para>
|
||||
<para>
|
||||
Although this will not be of interest to the majority of Spring
|
||||
users, those doing programmatic AOP work with EJBs may want to look at
|
||||
<classname>LocalSlsbInvokerInterceptor</classname>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-remote">
|
||||
<title>Accessing remote SLSBs</title>
|
||||
<para>
|
||||
Accessing remote EJBs is essentially identical to accessing local
|
||||
EJBs, except that the
|
||||
<classname>SimpleRemoteStatelessSessionProxyFactoryBean</classname> or
|
||||
<literal><jee:remote-slsb></literal> configuration element is used.
|
||||
Of course, with or without Spring, remote invocation semantics apply; a
|
||||
call to a method on an object in another VM in another computer does
|
||||
sometimes have to be treated differently in terms of usage scenarios and
|
||||
failure handling.
|
||||
</para>
|
||||
<para>
|
||||
Spring's EJB client support adds one more advantage over the
|
||||
non-Spring approach. Normally it is problematic for EJB client code to
|
||||
be easily switched back and forth between calling EJBs locally or
|
||||
remotely. This is because the remote interface methods must declare that
|
||||
they throw <classname>RemoteException</classname>, and client code must deal
|
||||
with this, while the local interface methods don't. Client code
|
||||
written for local EJBs which needs to be moved to remote EJBs
|
||||
typically has to be modified to add handling for the remote exceptions,
|
||||
and client code written for remote EJBs which needs to be moved to local
|
||||
EJBs, can either stay the same but do a lot of unnecessary handling of
|
||||
remote exceptions, or needs to be modified to remove that code. With the
|
||||
Spring remote EJB proxy, you can instead not declare any thrown
|
||||
<classname>RemoteException</classname> in your Business Method Interface and
|
||||
implementing EJB code, have a remote interface which is identical except
|
||||
that it does throw <classname>RemoteException</classname>, and rely on the
|
||||
proxy to dynamically treat the two interfaces as if they were the same.
|
||||
That is, client code does not have to deal with the checked
|
||||
<classname>RemoteException</classname> class. Any actual
|
||||
<classname>RemoteException</classname> that is thrown during the EJB
|
||||
invocation will be re-thrown as the non-checked
|
||||
<classname>RemoteAccessException</classname> class, which is a subclass of
|
||||
<classname>RuntimeException</classname>. The target service can then be
|
||||
switched at will between a local EJB or remote EJB (or even plain Java
|
||||
object) implementation, without the client code knowing or caring. Of
|
||||
course, this is optional; there is nothing stopping you from declaring
|
||||
<classname>RemoteExceptions</classname> in your business interface.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-ejb2-ejb3">
|
||||
<title>Accessing EJB 2.x SLSBs versus EJB 3 SLSBs</title>
|
||||
<para>
|
||||
Accessing EJB 2.x Session Beans and EJB 3 Session Beans via Spring
|
||||
is largely transparent. Spring's EJB accessors, including the
|
||||
<literal><jee:local-slsb></literal> and <literal><jee:remote-slsb></literal>
|
||||
facilities, transparently adapt to the actual component at runtime.
|
||||
They handle a home interface if found (EJB 2.x style), or perform straight
|
||||
component invocations if no home interface is available (EJB 3 style).
|
||||
</para>
|
||||
<para>
|
||||
Note: For EJB 3 Session Beans, you could effectively use a
|
||||
<classname>JndiObjectFactoryBean</classname> / <literal><jee:jndi-lookup></literal>
|
||||
as well, since fully usable component references are exposed for plain
|
||||
JNDI lookups there. Defining explicit <literal><jee:local-slsb></literal>
|
||||
/ <literal><jee:remote-slsb></literal> lookups simply provides
|
||||
consistent and more explicit EJB access configuration.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="ejb-implementation">
|
||||
<title>Using Spring's EJB implementation support classes</title>
|
||||
|
||||
<section id="ejb-implementation-ejb2">
|
||||
<title>EJB 2.x base classes</title>
|
||||
<para>
|
||||
Spring provides convenience classes to help you implement EJBs.
|
||||
These are designed to encourage the good practice of putting business
|
||||
logic behind EJBs in POJOs, leaving EJBs responsible for transaction
|
||||
demarcation and (optionally) remoting.
|
||||
</para>
|
||||
<para>
|
||||
To implement a Stateless or Stateful session bean, or a Message Driven
|
||||
bean, you need only derive your implementation class from
|
||||
<classname>AbstractStatelessSessionBean</classname>,
|
||||
<classname>AbstractStatefulSessionBean</classname>, and
|
||||
<classname>AbstractMessageDrivenBean</classname>/<classname>AbstractJmsMessageDrivenBean</classname>,
|
||||
respectively.
|
||||
</para>
|
||||
<para>
|
||||
Consider an example Stateless Session bean which actually delegates
|
||||
the implementation to a plain java service object. We have the business interface:
|
||||
</para>
|
||||
<programlisting><![CDATA[public interface MyComponent {
|
||||
public void myMethod(...);
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>We also have the plain Java implementation object:</para>
|
||||
<programlisting><![CDATA[public class MyComponentImpl implements MyComponent {
|
||||
public String myMethod(...) {
|
||||
...
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>And finally the Stateless Session Bean itself:</para>
|
||||
<programlisting><![CDATA[public class MyFacadeEJB extends AbstractStatelessSessionBean
|
||||
implements MyFacadeLocal {
|
||||
|
||||
private MyComponent myComp;
|
||||
|
||||
/**
|
||||
* Obtain our POJO service object from the BeanFactory/ApplicationContext
|
||||
* @see org.springframework.ejb.support.AbstractStatelessSessionBean#onEjbCreate()
|
||||
*/
|
||||
protected void onEjbCreate() throws CreateException {
|
||||
myComp = (MyComponent) getBeanFactory().getBean(
|
||||
ServicesConstants.CONTEXT_MYCOMP_ID);
|
||||
}
|
||||
|
||||
// for business method, delegate to POJO service impl.
|
||||
public String myFacadeMethod(...) {
|
||||
return myComp.myMethod(...);
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
The Spring EJB support base classes will by default create and load
|
||||
a Spring IoC container as part of their lifecycle, which is then available
|
||||
to the EJB (for example, as used in the code above to obtain the POJO
|
||||
service object). The loading is done via a strategy object which is a subclass of
|
||||
<classname>BeanFactoryLocator</classname>. The actual implementation of
|
||||
<classname>BeanFactoryLocator</classname> used by default is
|
||||
<classname>ContextJndiBeanFactoryLocator</classname>, which creates the
|
||||
ApplicationContext from a resource locations specified as a JNDI
|
||||
environment variable (in the case of the EJB classes, at
|
||||
<literal>java:comp/env/ejb/BeanFactoryPath</literal>). If there is a need
|
||||
to change the BeanFactory/ApplicationContext loading strategy, the default
|
||||
<classname>BeanFactoryLocator</classname> implementation used may be overridden
|
||||
by calling the <literal>setBeanFactoryLocator()</literal> method, either
|
||||
in <literal>setSessionContext()</literal>, or in the actual constructor of
|
||||
the EJB. Please see the Javadocs for more details.
|
||||
</para>
|
||||
<para>
|
||||
As described in the Javadocs, Stateful Session beans expecting to be
|
||||
passivated and reactivated as part of their lifecycle, and which use a
|
||||
non-serializable container instance (which is the normal case) will have
|
||||
to manually call <literal>unloadBeanFactory()</literal> and
|
||||
<literal>loadBeanFactory</literal> from <literal>ejbPassivate</literal>
|
||||
and <literal>ejbActivate</literal>, respectively, to unload and reload the
|
||||
BeanFactory on passivation and activation, since it can not be saved by
|
||||
the EJB container.
|
||||
</para>
|
||||
<para>
|
||||
The default behavior of the <classname>ContextJndiBeanFactoryLocator</classname>
|
||||
classes which is to load an <classname>ApplicationContext</classname> for the
|
||||
use of the EJB is adequate for some situations. However, it is problematic when
|
||||
the <classname>ApplicationContext</classname> is loading a number
|
||||
of beans, or the initialization of those beans is time consuming or memory
|
||||
intensive (such as a Hibernate <classname>SessionFactory</classname> initialization, for
|
||||
example), since every EJB will have their own copy. In this case, the user
|
||||
may want to override the default <classname>ContextJndiBeanFactoryLocator</classname>
|
||||
usage and use another <classname>BeanFactoryLocator</classname> variant, such as the
|
||||
<classname>ContextSingletonBeanFactoryLocator</classname> which can load and use a
|
||||
shared container to be used by multiple EJBs or other clients. Doing this is relatively
|
||||
simple, by adding code similar to this to the EJB:
|
||||
</para>
|
||||
<programlisting><![CDATA[ /**
|
||||
* Override default BeanFactoryLocator implementation
|
||||
* @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
|
||||
*/
|
||||
public void setSessionContext(SessionContext sessionContext) {
|
||||
super.setSessionContext(sessionContext);
|
||||
setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());
|
||||
setBeanFactoryLocatorKey(ServicesConstants.PRIMARY_CONTEXT_ID);
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
You would then need to create a bean definition file named <literal>beanRefContext.xml</literal>.
|
||||
This file defines all bean factories (usually in the form of application contexts) that may be used
|
||||
in the EJB. In many cases, this file will only contain a single bean definition such as this (where
|
||||
<literal>businessApplicationContext.xml</literal> contains the bean definitions for all business
|
||||
service POJOs):
|
||||
</para>
|
||||
<programlisting><![CDATA[<beans>
|
||||
<bean id="businessBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
|
||||
<constructor-arg value="businessApplicationContext.xml" />
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
<para>
|
||||
In the above example, the <literal>ServicesConstants.PRIMARY_CONTEXT_ID</literal> constant
|
||||
would be defined as follows:
|
||||
</para>
|
||||
<programlisting><![CDATA[public static final String ServicesConstants.PRIMARY_CONTEXT_ID = "businessBeanFactory";]]></programlisting>
|
||||
<para>
|
||||
Please see the respective Javadocs for the <classname>BeanFactoryLocator</classname> and
|
||||
<classname>ContextSingletonBeanFactoryLocator</classname> classes for more information on
|
||||
their usage.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-implementation-ejb3">
|
||||
<title>EJB 3 injection interceptor</title>
|
||||
<para>
|
||||
For EJB 3 Session Beans and Message-Driven Beans, Spring provides a convenient
|
||||
interceptor that resolves Spring 2.5's <literal>@Autowired</literal> annotation
|
||||
in the EJB component class:
|
||||
<classname>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</classname>.
|
||||
This interceptor can be applied through an <code>@Interceptors</code> annotation
|
||||
in the EJB component class, or through an <literal>interceptor-binding</literal>
|
||||
XML element in the EJB deployment descriptor.
|
||||
</para>
|
||||
<programlisting><![CDATA[@Stateless
|
||||
@Interceptors(SpringBeanAutowiringInterceptor.class)
|
||||
public class MyFacadeEJB implements MyFacadeLocal {
|
||||
|
||||
// automatically injected with a matching Spring bean
|
||||
@Autowired
|
||||
private MyComponent myComp;
|
||||
|
||||
// for business method, delegate to POJO service impl.
|
||||
public String myFacadeMethod(...) {
|
||||
return myComp.myMethod(...);
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
<classname>SpringBeanAutowiringInterceptor</classname> by default obtains target
|
||||
beans from a <classname>ContextSingletonBeanFactoryLocator</classname>, with the
|
||||
context defined in a bean definition file named <literal>beanRefContext.xml</literal>.
|
||||
By default, a single context definition is expected, which is obtained by type rather
|
||||
than by name. However, if you need to choose between multiple context definitions,
|
||||
a specific locator key is required. The locator key (i.e. the name of the context
|
||||
definition in <literal>beanRefContext.xml</literal>) can be explicitly specified
|
||||
either through overriding the <literal>getBeanFactoryLocatorKey</literal> method
|
||||
in a custom <classname>SpringBeanAutowiringInterceptor</classname> subclass.
|
||||
</para>
|
||||
<para>
|
||||
Alternatively, consider overriding <classname>SpringBeanAutowiringInterceptor</classname>'s
|
||||
<literal>getBeanFactory</literal> method, e.g. obtaining a shared
|
||||
<interfacename>ApplicationContext</interfacename> from a custom holder class.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,403 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="mail">
|
||||
<title>Email</title>
|
||||
|
||||
<section id="mail-introduction">
|
||||
<title>Introduction</title>
|
||||
<sidebar>
|
||||
<title>Library dependencies</title>
|
||||
<para>The following additional jars to be on the classpath of your
|
||||
application in order to be able to use the Spring Framework's email library.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://java.sun.com/products/javamail/">JavaMail</ulink> <filename class="libraryfile">mail.jar</filename> library</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://java.sun.com/products/javabeans/jaf/downloads/index.html">JAF</ulink> <filename class="libraryfile">activation.jar</filename> library</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>All of these libraries are available in the Spring-with-dependencies
|
||||
distribution of the Spring Framework (in addition to also being freely
|
||||
available on the web).</para>
|
||||
</sidebar>
|
||||
|
||||
<para>The Spring Framework provides a helpful utility library for sending
|
||||
email that shields the user from the specifics of the underlying mailing
|
||||
system and is responsible for low level resource handling on behalf of
|
||||
the client.</para>
|
||||
|
||||
<para>The <literal>org.springframework.mail</literal> package is the root level package
|
||||
for the Spring Framework's email support. The central interface for sending
|
||||
emails is the <interfacename>MailSender</interfacename> interface; a simple value object
|
||||
encapsulating the properties of a simple mail such as <emphasis>from</emphasis> and
|
||||
<emphasis>to</emphasis> (plus many others) is the <classname>SimpleMailMessage</classname> class.
|
||||
This package also contains a hierarchy of checked exceptions which provide
|
||||
a higher level of abstraction over the lower level mail system exceptions
|
||||
with the root exception being <exceptionname>MailException</exceptionname>. Please
|
||||
refer to the Javadocs for more information on the rich mail exception hierarchy.</para>
|
||||
|
||||
<para>The <interfacename>org.springframework.mail.javamail.JavaMailSender</interfacename>
|
||||
interface adds specialized <emphasis>JavaMail</emphasis> features such as MIME
|
||||
message support to the <interfacename>MailSender</interfacename> interface
|
||||
(from which it inherits). <interfacename>JavaMailSender</interfacename> also provides a
|
||||
callback interface for preparation of JavaMail MIME messages, called
|
||||
<interfacename>org.springframework.mail.javamail.MimeMessagePreparator</interfacename></para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="mail-usage">
|
||||
<title>Usage</title>
|
||||
<para>Let's assume there is a business interface called <interfacename>OrderManager</interfacename>:</para>
|
||||
<programlisting><![CDATA[public interface OrderManager {
|
||||
|
||||
void placeOrder(Order order);
|
||||
}]]></programlisting>
|
||||
|
||||
<para>Let us also assume that there is a requirement stating that an email message
|
||||
with an order number needs to be generated and sent to a customer placing the
|
||||
relevant order.</para>
|
||||
|
||||
<section id="mail-usage-simple">
|
||||
<title>Basic <interfacename>MailSender</interfacename> and <classname>SimpleMailMessage</classname> usage</title>
|
||||
<programlisting><![CDATA[import org.springframework.mail.MailException;
|
||||
import org.springframework.mail.MailSender;
|
||||
import org.springframework.mail.SimpleMailMessage;
|
||||
|
||||
public class SimpleOrderManager implements OrderManager {
|
||||
|
||||
private MailSender mailSender;
|
||||
private SimpleMailMessage templateMessage;
|
||||
|
||||
public void setMailSender(MailSender mailSender) {
|
||||
this.mailSender = mailSender;
|
||||
}
|
||||
|
||||
public void setTemplateMessage(SimpleMailMessage templateMessage) {
|
||||
this.templateMessage = templateMessage;
|
||||
}
|
||||
|
||||
public void placeOrder(Order order) {
|
||||
|
||||
]]><lineannotation>// Do the business calculations...</lineannotation><![CDATA[
|
||||
|
||||
]]><lineannotation>// Call the collaborators to persist the order...</lineannotation><![CDATA[
|
||||
|
||||
]]><lineannotation>// Create a thread safe "copy" of the template message and customize it</lineannotation><![CDATA[
|
||||
SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
|
||||
msg.setTo(order.getCustomer().getEmailAddress());
|
||||
msg.setText(
|
||||
"Dear " + order.getCustomer().getFirstName()
|
||||
+ order.getCustomer().getLastName()
|
||||
+ ", thank you for placing order. Your order number is "
|
||||
+ order.getOrderNumber());
|
||||
try{
|
||||
this.mailSender.send(msg);
|
||||
}
|
||||
catch(MailException ex) {
|
||||
]]><lineannotation>// simply log it and go on...</lineannotation><![CDATA[
|
||||
System.err.println(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>Find below the bean definitions for the above code:</para>
|
||||
<programlisting><![CDATA[<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
|
||||
<property name="host" value="mail.mycompany.com"/>
|
||||
</bean>
|
||||
|
||||
]]><lineannotation><!-- this is a template message that we can pre-load with default state --></lineannotation><![CDATA[
|
||||
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage">
|
||||
<property name="from" value="customerservice@mycompany.com"/>
|
||||
<property name="subject" value="Your order"/>
|
||||
</bean>
|
||||
|
||||
<bean id="orderManager" class="com.mycompany.businessapp.support.SimpleOrderManager">
|
||||
<property name="mailSender" ref="mailSender"/>
|
||||
<property name="templateMessage" ref="templateMessage"/>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="mail-usage-mime">
|
||||
<title>Using the <interfacename>JavaMailSender</interfacename> and the <classname>MimeMessagePreparator</classname></title>
|
||||
<para>Here is another implementation of <interfacename>OrderManager</interfacename> using
|
||||
the <interfacename>MimeMessagePreparator</interfacename> callback interface. Please note
|
||||
in this case that the <literal>mailSender</literal> property is of type
|
||||
<interfacename>JavaMailSender</interfacename> so that we are able to use the JavaMail
|
||||
<classname>MimeMessage</classname> class:</para>
|
||||
|
||||
<programlisting><![CDATA[import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import org.springframework.mail.MailException;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessagePreparator;
|
||||
|
||||
public class SimpleOrderManager implements OrderManager {
|
||||
|
||||
private JavaMailSender mailSender;
|
||||
|
||||
public void setMailSender(JavaMailSender mailSender) {
|
||||
this.mailSender = mailSender;
|
||||
}
|
||||
|
||||
public void placeOrder(final Order order) {
|
||||
|
||||
]]><lineannotation>// Do the business calculations...</lineannotation><![CDATA[
|
||||
|
||||
]]><lineannotation>// Call the collaborators to persist the order...</lineannotation><![CDATA[
|
||||
|
||||
MimeMessagePreparator preparator = new MimeMessagePreparator() {
|
||||
|
||||
public void prepare(MimeMessage mimeMessage) throws Exception {
|
||||
|
||||
mimeMessage.setRecipient(Message.RecipientType.TO,
|
||||
new InternetAddress(order.getCustomer().getEmailAddress()));
|
||||
mimeMessage.setFrom(new InternetAddress("mail@mycompany.com"));
|
||||
mimeMessage.setText(
|
||||
"Dear " + order.getCustomer().getFirstName() + " "
|
||||
+ order.getCustomer().getLastName()
|
||||
+ ", thank you for placing order. Your order number is "
|
||||
+ order.getOrderNumber());
|
||||
}
|
||||
};
|
||||
try {
|
||||
this.mailSender.send(preparator);
|
||||
}
|
||||
catch (MailException ex) {
|
||||
]]><lineannotation>// simply log it and go on...</lineannotation><![CDATA[
|
||||
System.err.println(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<note>
|
||||
<para>The mail code is a crosscutting concern and could well be a candidate
|
||||
for refactoring into a <link linkend="aop">custom Spring AOP aspect</link>,
|
||||
which then could be executed at appropriate joinpoints on the
|
||||
<interfacename>OrderManager</interfacename> target.</para>
|
||||
</note>
|
||||
|
||||
<para>The Spring Framework's mail support ships with two
|
||||
<interfacename>MailSender</interfacename> implementations. The standard JavaMail
|
||||
implementation and the implementation on top of Jason Hunter's
|
||||
<classname>MailMessage</classname> class that is included in
|
||||
<ulink url="http://servlets.com/cos">the <literal>com.oreilly.servlet</literal>
|
||||
package</ulink>. Please refer to the relevant Javadocs for more information.</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="mail-javamail-mime">
|
||||
<title>Using the JavaMail <classname>MimeMessageHelper</classname></title>
|
||||
|
||||
<para>A class that comes in pretty handy when dealing with JavaMail messages is
|
||||
the <classname>org.springframework.mail.javamail.MimeMessageHelper</classname> class,
|
||||
which shields you from having to use the verbose JavaMail API. Using
|
||||
the <classname>MimeMessageHelper</classname> it is pretty easy to
|
||||
create a <classname>MimeMessage</classname>:</para>
|
||||
<programlisting><lineannotation>// of course you would use DI in any real-world cases</lineannotation><![CDATA[
|
||||
JavaMailSenderImpl sender = new JavaMailSenderImpl();
|
||||
sender.setHost("mail.host.com");
|
||||
|
||||
MimeMessage message = sender.createMimeMessage();
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message);
|
||||
helper.setTo("test@host.com");
|
||||
helper.setText("Thank you for ordering!");
|
||||
|
||||
sender.send(message);]]></programlisting>
|
||||
|
||||
<section id="mail-javamail-mime-attachments">
|
||||
<title>Sending attachments and inline resources</title>
|
||||
<para>Multipart email messages allow for both attachments and inline resources.
|
||||
Examples of inline resources would be be images or a stylesheet you want to use
|
||||
in your message, but that you don't want displayed as an attachment.</para>
|
||||
<section id="mail-javamail-mime-attachments-attachment">
|
||||
<title>Attachments</title>
|
||||
<para>The following example shows you how to use the
|
||||
<classname>MimeMessageHelper</classname> to send an email along with a
|
||||
single JPEG image attachment.</para>
|
||||
<programlisting><![CDATA[JavaMailSenderImpl sender = new JavaMailSenderImpl();
|
||||
sender.setHost("mail.host.com");
|
||||
|
||||
MimeMessage message = sender.createMimeMessage();
|
||||
|
||||
]]><lineannotation>// use the true flag to indicate you need a multipart message</lineannotation><![CDATA[
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
helper.setTo("test@host.com");
|
||||
|
||||
helper.setText("Check out this image!");
|
||||
|
||||
]]><lineannotation>// let's attach the infamous windows Sample file (this time copied to c:/)</lineannotation><![CDATA[
|
||||
FileSystemResource file = new FileSystemResource(new File("c:/Sample.jpg"));
|
||||
helper.addAttachment("CoolImage.jpg", file);
|
||||
|
||||
sender.send(message);]]></programlisting>
|
||||
</section>
|
||||
<section id="mail-javamail-mime-attachments-inline">
|
||||
<title>Inline resources</title>
|
||||
<para>The following example shows you how to use the
|
||||
<classname>MimeMessageHelper</classname> to send an email along with an
|
||||
inline image.</para>
|
||||
<programlisting><![CDATA[JavaMailSenderImpl sender = new JavaMailSenderImpl();
|
||||
sender.setHost("mail.host.com");
|
||||
|
||||
MimeMessage message = sender.createMimeMessage();
|
||||
|
||||
]]><lineannotation>// use the true flag to indicate you need a multipart message</lineannotation><![CDATA[
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
helper.setTo("test@host.com");
|
||||
|
||||
]]><lineannotation>// use the true flag to indicate the text included is HTML</lineannotation><![CDATA[
|
||||
helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true);
|
||||
|
||||
]]><lineannotation>// let's include the infamous windows Sample file (this time copied to c:/)</lineannotation><![CDATA[
|
||||
FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg"));
|
||||
helper.addInline("identifier1234", res);
|
||||
|
||||
sender.send(message);]]></programlisting>
|
||||
<warning>
|
||||
<para>Inline resources are added to the mime message using the
|
||||
specified <literal>Content-ID</literal> (<literal>identifier1234</literal>
|
||||
in the above example). The order in which you are adding the text and the
|
||||
resource are <emphasis role="bold">very</emphasis> important. Be sure to
|
||||
<emphasis>first add the text</emphasis> and after that the resources. If
|
||||
you are doing it the other way around, it won't work!</para>
|
||||
</warning>
|
||||
</section>
|
||||
</section>
|
||||
<section id="mail-templates">
|
||||
<title>Creating email content using a templating library</title>
|
||||
<para>The code in the previous examples explicitly has been creating the
|
||||
content of the email message, using methods calls such as
|
||||
<methodname>message.setText(..)</methodname>. This is fine for
|
||||
simple cases, and it is okay in the context of the aforementioned
|
||||
examples, where the intent was to show you the very basics of the API.</para>
|
||||
<para>In your typical enterprise application though, you are not going
|
||||
to create the content of your emails using the above approach for a number
|
||||
of reasons.</para>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Creating HTML-based email content in Java code is tedious and error prone</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>There is no clear separation between display logic and business logic</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Changing the display structure of the email content requires writing Java code, recompiling, redeploying...</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>Typically the approach taken to address these issues is to use a template library
|
||||
such as FreeMarker or Velocity to define the display structure of email content. This leaves
|
||||
your code tasked only with creating the data that is to be rendered in the email
|
||||
template and sending the email. It is definitely a best practice for when
|
||||
the content of your emails becomes even moderately complex, and with
|
||||
the Spring Framework's support classes for FreeMarker and Velocity becomes
|
||||
quite easy to do. Find below an example of using the Velocity template library
|
||||
to create email content.</para>
|
||||
<section id="mail-templates-example">
|
||||
<title>A Velocity-based example</title>
|
||||
<para>To use <ulink url="http://velocity.apache.org">Velocity</ulink> to
|
||||
create your email template(s), you will need to have the Velocity libraries
|
||||
available on your classpath. You will also need to create one or more Velocity templates
|
||||
for the email content that your application needs. Find below the Velocity
|
||||
template that this example will be using... as you can see it is HTML-based,
|
||||
and since it is plain text it can be created using your favorite HTML editor
|
||||
without recourse to having to know Java.</para>
|
||||
<programlisting><lineannotation># in the <literal>com/foo/package</literal></lineannotation><![CDATA[
|
||||
<html>
|
||||
<body>
|
||||
<h3>Hi ${user.userName}, welcome to the Chipping Sodbury On-the-Hill message boards!</h3>
|
||||
|
||||
<div>
|
||||
Your email address is <a href="mailto:${user.emailAddress}">${user.emailAddress}</a>.
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>]]></programlisting>
|
||||
<para>Find below some simple code and Spring XML configuration that
|
||||
makes use of the above Velocity template to create email content and
|
||||
send email(s).</para>
|
||||
<programlisting><![CDATA[package com.foo;
|
||||
|
||||
import org.apache.velocity.app.VelocityEngine;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.mail.javamail.MimeMessagePreparator;
|
||||
import org.springframework.ui.velocity.VelocityEngineUtils;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SimpleRegistrationService implements RegistrationService {
|
||||
|
||||
private JavaMailSender mailSender;
|
||||
private VelocityEngine velocityEngine;
|
||||
|
||||
public void setMailSender(JavaMailSender mailSender) {
|
||||
this.mailSender = mailSender;
|
||||
}
|
||||
|
||||
public void setVelocityEngine(VelocityEngine velocityEngine) {
|
||||
this.velocityEngine = velocityEngine;
|
||||
}
|
||||
|
||||
public void register(User user) {
|
||||
|
||||
]]><lineannotation>// Do the registration logic...</lineannotation><![CDATA[
|
||||
|
||||
sendConfirmationEmail(user);
|
||||
}
|
||||
|
||||
private void sendConfirmationEmail(final User user) {
|
||||
MimeMessagePreparator preparator = new MimeMessagePreparator() {
|
||||
public void prepare(MimeMessage mimeMessage) throws Exception {
|
||||
MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
|
||||
message.setTo(user.getEmailAddress());
|
||||
message.setFrom("webmaster@csonth.gov.uk"); ]]><lineannotation>// could be parameterized...</lineannotation><![CDATA[
|
||||
Map model = new HashMap();
|
||||
model.put("user", user);
|
||||
String text = VelocityEngineUtils.mergeTemplateIntoString(
|
||||
velocityEngine, "com/dns/registration-confirmation.vm", model);
|
||||
message.setText(text, true);
|
||||
}
|
||||
};
|
||||
this.mailSender.send(preparator);
|
||||
}
|
||||
}]]></programlisting>
|
||||
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
|
||||
<property name="host" value="mail.csonth.gov.uk"/>
|
||||
</bean>
|
||||
|
||||
<bean id="registrationService" class="com.foo.SimpleRegistrationService">
|
||||
<property name="mailSender" ref="mailSender"/>
|
||||
<property name="velocityEngine" ref="velocityEngine"/>
|
||||
</bean>
|
||||
|
||||
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
|
||||
<property name="velocityProperties">
|
||||
<value>
|
||||
resource.loader=class
|
||||
class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,503 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<chapter id="metadata">
|
||||
<title>Annotations and Source Level Metadata Support</title>
|
||||
<section id="metadata-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>Source-level metadata is the addition of <emphasis>attributes</emphasis> or
|
||||
<emphasis>annotations</emphasis> to program elements - usually, classes
|
||||
and/or methods.</para>
|
||||
<para>For example, we might add metadata to a class as follows:</para>
|
||||
<programlisting><![CDATA[/**
|
||||
* Normal comments here
|
||||
* @@org.springframework.transaction.interceptor.DefaultTransactionAttribute()
|
||||
*/
|
||||
public class PetStoreImpl implements PetStoreFacade, OrderService {]]></programlisting>
|
||||
<para>We could add metadata to a method as follows:</para>
|
||||
<programlisting><![CDATA[/**
|
||||
* Normal comments here
|
||||
* @@org.springframework.transaction.interceptor.RuleBasedTransactionAttribute()
|
||||
* @@org.springframework.transaction.interceptor.RollbackRuleAttribute(Exception.class)
|
||||
* @@org.springframework.transaction.interceptor.NoRollbackRuleAttribute("ServletException")
|
||||
*/
|
||||
public void echoException(Exception ex) throws Exception {
|
||||
....
|
||||
}]]></programlisting>
|
||||
<para>Both of these examples use Jakarta Commons Attributes syntax.</para>
|
||||
<para>
|
||||
Source-level metadata was introduced to the mainstream by XDoclet
|
||||
(in the Java world) and by the release of Microsoft's .NET platform, which
|
||||
uses source-level attributes to control transactions, pooling and other
|
||||
behavior.
|
||||
</para>
|
||||
<para>
|
||||
The value in this approach has been recognized in the J2EE
|
||||
community. For example, it's much less verbose than the traditional XML
|
||||
deployment descriptors used exclusively by EJB. While it is desirable to
|
||||
externalize some things from program source code, some important
|
||||
enterprise settings - notably transaction characteristics - arguably belong
|
||||
in program source. Contrary to the assumptions of the EJB spec, it seldom
|
||||
makes sense to modify the transactional characteristics of a method
|
||||
(although parameters like transaction timeouts might change!).
|
||||
</para>
|
||||
<para>
|
||||
Although metadata attributes are typically used mainly by framework
|
||||
infrastructure to describe the services application classes require, it
|
||||
should also be possible for metadata attributes to be queried at runtime.
|
||||
This is a key distinction from solutions such as XDoclet, which
|
||||
view metadata primarily as a way of generating code such as EJB artefacts.
|
||||
</para>
|
||||
<para>
|
||||
There are a number of solutions in this space, including:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">Standard Java Annotations</emphasis>: the
|
||||
standard Java metadata implementation (developed as JSR-175 and available
|
||||
in Java 5). Spring has specific Java 5 annotations for transactional
|
||||
demarcation, JMX, and aspects (to be precise they are AspectJ annotations).
|
||||
However, since Spring supports Java 1.4 as well, a solution for said
|
||||
JVM versions is needed too. Spring metadata support provides such a
|
||||
solution.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">XDoclet</emphasis>: well-established
|
||||
solution, primarily intended for code generation.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Various <emphasis role="bold">open source attribute
|
||||
implementations</emphasis>, for Java 1.4, of which Commons
|
||||
Attributes is the most complete implementation. All these require
|
||||
a special pre- or post-compilation step.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section id="metadata-spring">
|
||||
<title>Spring's metadata support</title>
|
||||
<para>In keeping with its provision of abstractions over important
|
||||
concepts, Spring provides a facade to metadata implementations, in the
|
||||
form of the <interfacename>org.springframework.metadata.Attributes</interfacename>
|
||||
interface. Such a facade adds value for several reasons:</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Even though Java 5 provides metadata support at language level, there will
|
||||
still be value in providing such an abstraction:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Java 5 metadata is static. It is associated with a class
|
||||
at compile time, and cannot be changed in a deployed
|
||||
environment (annotation state can actually be changed
|
||||
at runtime using reflection, but doing so would really be
|
||||
a bad practice). There is a need for hierarchical metadata,
|
||||
providing the ability to override certain attribute values in
|
||||
deployment - for example, in an XML file.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Java 5 metadata is returned through the Java reflection
|
||||
API. This makes it impossible to mock during test time. Spring
|
||||
provides a simple interface to allow this.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>There will be a need for metadata support in 1.3 and 1.4
|
||||
applications for at least two years. Spring aims to provide
|
||||
working solutions <emphasis>now</emphasis>; forcing the use of
|
||||
Java 5 is not an option in such an important area.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Current metadata APIs, such as Commons Attributes (used by
|
||||
Spring 1.0-1.2) are hard to test. Spring provides a simple metadata
|
||||
interface that is much easier to mock.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>The Spring <interfacename>Attributes</interfacename> interface looks like this:</para>
|
||||
<programlisting><![CDATA[public interface Attributes {
|
||||
|
||||
Collection getAttributes(Class targetClass);
|
||||
|
||||
Collection getAttributes(Class targetClass, Class filter);
|
||||
|
||||
Collection getAttributes(Method targetMethod);
|
||||
|
||||
Collection getAttributes(Method targetMethod, Class filter);
|
||||
|
||||
Collection getAttributes(Field targetField);
|
||||
|
||||
Collection getAttributes(Field targetField, Class filter);
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
This is a lowest common denominator interface. JSR-175 offers more
|
||||
capabilities than this, such as attributes on method arguments.
|
||||
</para>
|
||||
<para>
|
||||
Note that this interface offers <classname>Object</classname>
|
||||
attributes, like .NET. This distinguishes it from attribute systems such
|
||||
as that of Nanning Aspects, which offer only <classname>String</classname>
|
||||
attributes. There is a significant advantage in supporting
|
||||
<classname>Object</classname> attributes, namely that it enables
|
||||
attributes to participate in class hierarchies and allows such
|
||||
attributes to react intelligently to their configuration parameters.
|
||||
</para>
|
||||
<para>
|
||||
With most attribute providers, attribute classes are configured
|
||||
via constructor arguments or JavaBean properties. Commons Attributes
|
||||
supports both.
|
||||
</para>
|
||||
<para>As with all Spring abstraction APIs, <interfacename>Attributes</interfacename>
|
||||
is an interface. This makes it easy to mock attribute implementations for unit tests.</para>
|
||||
</section>
|
||||
<section id="metadata-annotations">
|
||||
<title>Annotations</title>
|
||||
<para>
|
||||
The Spring Framework ships with a number of custom Java 5+ annotations.
|
||||
</para>
|
||||
<section id="metadata-annotations-required">
|
||||
<title><interfacename>@Required</interfacename></title>
|
||||
<para>The <interfacename>@Required</interfacename> annotation in the
|
||||
<literal>org.springframework.beans.factory.annotation</literal>
|
||||
package can be used to <emphasis>mark</emphasis> a property as
|
||||
being <emphasis>'required-to-be-set'</emphasis> (i.e. an
|
||||
annotated (setter) method of a class must be configured to be
|
||||
dependency injected with a value), else an
|
||||
<classname>Exception</classname> will be thrown by the container
|
||||
at runtime.</para>
|
||||
<para>The best way to illustrate the usage of this annotation is to
|
||||
show an example:</para>
|
||||
<programlisting><![CDATA[public class SimpleMovieLister {
|
||||
|
||||
]]><lineannotation>// the <classname>SimpleMovieLister</classname> has a dependency on the <interfacename>MovieFinder</interfacename></lineannotation><![CDATA[
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
]]><lineannotation>// a setter method so that the Spring container can 'inject' a <interfacename>MovieFinder</interfacename></lineannotation><![CDATA[
|
||||
@Required
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
|
||||
]]><lineannotation>// business logic that actually 'uses' the injected <interfacename>MovieFinder</interfacename> is omitted...</lineannotation><![CDATA[
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
Hopefully the above class definition reads easy on the eye.
|
||||
Any and all <interfacename>BeanDefinitions</interfacename> for the
|
||||
<classname>SimpleMovieLister</classname> class must be provided
|
||||
with a value.
|
||||
</para>
|
||||
<para>
|
||||
Let's look at an example of some XML configuration that will
|
||||
<emphasis role="bold">not</emphasis> pass validation.
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean id="movieLister" class="x.y.SimpleMovieLister">
|
||||
]]><lineannotation><!-- whoops, no MovieFinder is set (and this property is <interfacename>@Required</interfacename>) --></lineannotation><![CDATA[
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
At runtime the following message will be generated by the Spring container
|
||||
(the rest of the stack trace has been truncated).
|
||||
</para>
|
||||
<programlisting><![CDATA[Exception in thread "main" java.lang.IllegalArgumentException:
|
||||
Property 'movieFinder' is required for bean 'movieLister'.]]></programlisting>
|
||||
<para>
|
||||
There is one last little (small, tiny) piece of Spring configuration
|
||||
that is required to actually <emphasis>'switch on'</emphasis> this
|
||||
behavior. Simply annotating the <emphasis>'setter'</emphasis> properties
|
||||
of your classes is not enough to get this behavior. You need
|
||||
to enable a component that is aware of the <interfacename>@Required</interfacename>
|
||||
annotation and that can process it appropriately.
|
||||
</para>
|
||||
<para>
|
||||
This component is the <classname>RequiredAnnotationBeanPostProcessor</classname> class.
|
||||
This is a special <interfacename>BeanPostProcessor</interfacename>
|
||||
implementation that is <interfacename>@Required</interfacename>-aware
|
||||
and actually provides the <emphasis>'blow up if this required property
|
||||
has not been set'</emphasis> logic. It is <emphasis>very</emphasis> easy
|
||||
to configure; simply drop the following bean definition into your Spring
|
||||
XML configuration.
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>]]></programlisting>
|
||||
<para>
|
||||
Finally, one can configure an instance of the
|
||||
<classname>RequiredAnnotationBeanPostProcessor</classname> class to look
|
||||
for <emphasis>another</emphasis> <interfacename>Annotation</interfacename> type.
|
||||
This is great if you already have your own
|
||||
<interfacename>@Required</interfacename>-style annotation. Simply plug it into
|
||||
the definition of a <classname>RequiredAnnotationBeanPostProcessor</classname> and
|
||||
you are good to go.
|
||||
</para>
|
||||
<para>
|
||||
By way of an example, let's suppose you (or your organization / team) have
|
||||
defined an attribute called @ <interfacename>Mandatory</interfacename>.
|
||||
You can make a <classname>RequiredAnnotationBeanPostProcessor</classname>
|
||||
instance <interfacename>@Mandatory</interfacename>-aware like so:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor">
|
||||
<property name="requiredAnnotationType" value="your.company.package.Mandatory"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
Here is the source code for the <interfacename>@Mandatory</interfacename>
|
||||
annotation. You will need to ensure that your custom annotation type
|
||||
is itself annotated with appropriate annotations for its target
|
||||
and runtime retention policy.
|
||||
</para>
|
||||
<programlisting><![CDATA[package your.company.package;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Mandatory {
|
||||
}]]></programlisting>
|
||||
</section>
|
||||
<section id="metadata-annotations-other">
|
||||
<title>Other @Annotations in Spring</title>
|
||||
<para>
|
||||
Annotations are also used in a number of other places throughout Spring.
|
||||
Rather than being described here, these annotations are described in that
|
||||
section or chapter of the reference documentation to which they are most
|
||||
relevant.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="transaction-declarative-annotations"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="aop-atconfigurable"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="aop-ataspectj"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="beans-annotation-config"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="beans-classpath-scanning"/></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
<section id="metadata-commons">
|
||||
<title>Integration with Jakarta Commons Attributes</title>
|
||||
<para>
|
||||
Presently Spring supports only Jakarta Commons Attributes out of the
|
||||
box, although it is easy to provide implementations of the
|
||||
<interfacename>org.springframework.metadata.Attributes</interfacename> interface for
|
||||
other metadata providers.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis role="bold">Commons Attributes 2.2</emphasis>
|
||||
(<ulink url="http://jakarta.apache.org/commons/attributes/">http://jakarta.apache.org/commons/attributes/</ulink>)
|
||||
is a capable attributes solution. It supports attribute configuration via
|
||||
constructor arguments and JavaBean properties, which offers better
|
||||
self-documentation in attribute definitions. (Support for JavaBean
|
||||
properties was added at the request of the Spring team.)
|
||||
</para>
|
||||
<para>
|
||||
We've already seen two examples of Commons Attributes attributes
|
||||
definitions. In general, we will need to express:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>The name of the attribute class</emphasis>. This can
|
||||
be a fully qualified name (FQN), as shown above. If the relevant attribute class has already
|
||||
been imported, the FQN isn't required. It's also possible to specify
|
||||
"attribute packages" in attribute compiler configuration.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Any necessary parameterization.</emphasis> This is done via
|
||||
constructor arguments or JavaBean properties.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>Bean properties look as follows:</para>
|
||||
<programlisting><![CDATA[/**
|
||||
* @@MyAttribute(myBooleanJavaBeanProperty=true)
|
||||
*/]]></programlisting>
|
||||
<para>
|
||||
It's possible to combine constructor arguments and JavaBean
|
||||
properties (as in Spring IoC).
|
||||
</para>
|
||||
<para>
|
||||
Because, unlike Java 1.5 attributes, Commons Attributes is not
|
||||
integrated with the Java language, it is necessary to run a special
|
||||
<emphasis>attribute compilation</emphasis> step as part of the build
|
||||
process.
|
||||
</para>
|
||||
<para>
|
||||
To run Commons Attributes as part of the build process, you will
|
||||
need to do the following:
|
||||
</para>
|
||||
<para>
|
||||
1. Copy the necessary library jars to
|
||||
<literal>$ANT_HOME/lib</literal>. Four Jars are required, and all are
|
||||
distributed with Spring:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>the Commons Attributes compiler jar and API jar</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>xJavadoc.jar from XDoclet</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>commons-collections.jar from Jakarta Commons</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
2. Import the Commons Attributes ant tasks into your project build
|
||||
script, as follows:
|
||||
</para>
|
||||
<programlisting><![CDATA[<taskdef resource="org/apache/commons/attributes/anttasks.properties"/>]]></programlisting>
|
||||
<para>
|
||||
3. Next, define an attribute compilation task, which will use the
|
||||
Commons Attributes attribute-compiler task to "compile" the attributes in
|
||||
the source. This process results in the generation of additional sources,
|
||||
to a location specified by the <literal>destdir</literal> attribute. Here we show the use of
|
||||
a temporary directory for storing the generated files:
|
||||
</para>
|
||||
<programlisting><![CDATA[<target name="compileAttributes">
|
||||
|
||||
<attribute-compiler destdir="${commons.attributes.tempdir}">
|
||||
<fileset dir="${src.dir}" includes="**/*.java"/>
|
||||
</attribute-compiler>
|
||||
|
||||
</target>]]></programlisting>
|
||||
<para>
|
||||
The compile target that runs javac over the sources should depend on
|
||||
this attribute compilation task, and must also compile the generated
|
||||
sources, which we output to our destination temporary directory. If there
|
||||
are syntax errors in your attribute definitions, they will normally be
|
||||
caught by the attribute compiler. However, if the attribute definitions
|
||||
are syntactically plausible, but specify invalid types or class names, the
|
||||
compilation of the generated attribute classes may fail. In this case, you
|
||||
can look at the generated classes to establish the cause of the
|
||||
problem.
|
||||
</para>
|
||||
<remark>
|
||||
Commons Attributes also provides Maven support. Please refer to
|
||||
Commons Attributes documentation for further information.
|
||||
</remark>
|
||||
<para>
|
||||
While this attribute compilation process may look complex, in fact
|
||||
it's a one-off cost. Once set up, attribute compilation is incremental, so
|
||||
it doesn't usually noticeably slow the build process. And once the
|
||||
compilation process is set up, you may find that use of attributes as
|
||||
described in this chapter can save you a lot of time in other
|
||||
areas.
|
||||
</para>
|
||||
<para>
|
||||
If you require attribute indexing support (only currently required
|
||||
by Spring for attribute-targeted web controllers, discussed below), you
|
||||
will need an additional step, which must be performed on a jar file of
|
||||
your compiled classes. In this additional step, Commons Attributes will
|
||||
create an index of all the attributes defined on your sources, for
|
||||
efficient lookup at runtime. The step looks like this:
|
||||
</para>
|
||||
<programlisting><![CDATA[<attribute-indexer jarFile="myCompiledSources.jar">
|
||||
|
||||
<classpath refid="master-classpath"/>
|
||||
|
||||
</attribute-indexer>]]></programlisting>
|
||||
<remark>
|
||||
See the <literal>/attributes</literal> directory of the Spring JPetStore sample
|
||||
application for an example of this build process. You can take the build
|
||||
script it contains and modify it for your own projects.
|
||||
</remark>
|
||||
<para>
|
||||
If your unit tests depend on attributes, try to express the
|
||||
dependency on the Spring Attributes abstraction, rather than Commons
|
||||
Attributes. Not only is this more portable - for example, your tests will
|
||||
still work if you switch to Java 1.5 attributes in future - it simplifies
|
||||
testing. Also, Commons Attributes is a static API, while Spring provides a
|
||||
metadata interface that you can easily mock.
|
||||
</para>
|
||||
</section>
|
||||
<section id="metadata-uses">
|
||||
<title>Metadata and Spring AOP autoproxying</title>
|
||||
<para>
|
||||
The most important uses of metadata attributes are in conjunction
|
||||
with Spring AOP. This provides a .NET-like programming model, where
|
||||
declarative services are automatically provided to application objects
|
||||
that declare metadata attributes. Such metadata attributes can be
|
||||
supported out of the box by the framework, as in the case of declarative
|
||||
transaction management, or can be custom.
|
||||
</para>
|
||||
<section id="metadata-fundamentals">
|
||||
<title>Fundamentals</title>
|
||||
<para>
|
||||
This builds on the Spring AOP autoproxy functionality.
|
||||
Configuration might look like this:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
|
||||
|
||||
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
|
||||
<property name="transactionInterceptor" ref="txInterceptor" />
|
||||
</bean>
|
||||
|
||||
<bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
|
||||
<property name="transactionManager" ref="transactionManager" />
|
||||
<property name="transactionAttributeSource">
|
||||
<bean class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource">
|
||||
<property name="attributes" ref="attributes" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes" />]]></programlisting>
|
||||
<para>
|
||||
The basic concepts here should be familiar from the discussion of
|
||||
autoproxying in the AOP chapter.
|
||||
</para>
|
||||
<para>
|
||||
The most important bean definitions are the auto-proxy creator
|
||||
and the advisor. Note that the actual bean names are not important;
|
||||
what matters is their class.
|
||||
</para>
|
||||
<para>
|
||||
The bean definition of class
|
||||
<classname>org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator</classname>
|
||||
will automatically advise ("auto-proxy") all bean instances in the
|
||||
current factory based on matching advisor implementations. This class
|
||||
knows nothing about attributes, but relies on advisors' pointcuts
|
||||
matching. The pointcuts, however, do know about attributes.
|
||||
</para>
|
||||
<para>
|
||||
Thus we simply need an AOP advisor that will provide declarative
|
||||
transaction management based on attributes.
|
||||
</para>
|
||||
<para>
|
||||
It is possible to add arbitrary custom advisor implementations as
|
||||
well, and they will also be evaluated and applied automatically. (You
|
||||
can use advisors whose pointcuts match on criteria besides attributes in
|
||||
the same autoproxy configuration, if necessary.)
|
||||
</para>
|
||||
<para>
|
||||
Finally, the <literal>attributes</literal> bean is the Commons
|
||||
Attributes Attributes implementation. Replace it with another
|
||||
implementation of the
|
||||
<interfacename>org.springframework.metadata.Attributes</interfacename>
|
||||
interface to source attributes from a different source.
|
||||
</para>
|
||||
</section>
|
||||
<section id="metadata-tx">
|
||||
<title>Declarative transaction management</title>
|
||||
<para>
|
||||
The most common use of source-level attributes is to provide
|
||||
declarative transaction management. Once the bean definitions
|
||||
shown above are in place, you can define any number of application
|
||||
objects requiring declarative transactions. Only those classes or
|
||||
methods with transaction attributes will be given transaction advice.
|
||||
You need to do nothing except define the required transaction
|
||||
attributes.
|
||||
</para>
|
||||
<para>Please note that you can specify transaction attributes at either class
|
||||
or method level. Class-level attributes, if specified, will be "inherited"
|
||||
by all methods whereas method attributes will wholly override any
|
||||
class-level attributes.</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,796 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="new-in-2">
|
||||
<title>What's new in Spring 2.0 and 2.5?</title>
|
||||
|
||||
<section id="new-in-2-intro">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>If you have been using the Spring Framework for some time, you will
|
||||
be aware that Spring has undergone two major revisions: Spring 2.0,
|
||||
released in October 2006, and Spring 2.5, released in November 2007.</para>
|
||||
|
||||
<sidebar id="new-in-2-intro-java">
|
||||
<title>Java SE and Java EE Support</title>
|
||||
|
||||
<para>The Spring Framework continues to be compatible with all versions
|
||||
of Java since (and including) Java 1.4.2. This means that Java 1.4.2,
|
||||
Java 5 and Java 6 are supported, although some advanced functionality of
|
||||
the Spring Framework will not be available to you if you are committed to
|
||||
using Java 1.4.2. Spring 2.5 introduces dedicated support for Java 6,
|
||||
after Spring 2.0's in-depth support for Java 5 throughout the
|
||||
framework.</para>
|
||||
|
||||
<para>Furthermore, Spring remains compatible with J2EE 1.3 and higher,
|
||||
while at the same time introducing dedicated support for Java EE 5. This
|
||||
means that Spring can be consistently used on application servers such
|
||||
as BEA WebLogic 8.1, 9.0, 9.2 and 10, IBM WebSphere 5.1, 6.0, 6.1 and 7,
|
||||
Oracle OC4J 10.1.3 and 11, JBoss 3.2, 4.0, 4.2 and 5.0, as well as Tomcat
|
||||
4.1, 5.0, 5.5 and 6.0, Jetty 4.2, 5.1 and 6.1, Resin 2.1, 3.0 and 3.1
|
||||
and GlassFish V1 and V2.</para>
|
||||
|
||||
<para><emphasis>NOTE: We generally recommend using the most recent
|
||||
version of each application server generation. In particular,
|
||||
make sure you are using BEA WebLogic 8.1 SP6 or higher and
|
||||
WebSphere 6.0.2.19 / 6.1.0.9 or higher, respectively, when using
|
||||
those WebLogic and WebSphere generations with Spring 2.5.</emphasis></para>
|
||||
</sidebar>
|
||||
|
||||
<para>This chapter is a guide to the new and improved features of Spring
|
||||
2.0 and 2.5. It is intended to provide a high-level summary so that
|
||||
seasoned Spring architects and developers can become immediately familiar
|
||||
with the new Spring 2.x functionality. For more in-depth information on
|
||||
the features, please refer to the corresponding sections hyperlinked from
|
||||
within this chapter.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-ioc">
|
||||
<title>The Inversion of Control (IoC) container</title>
|
||||
|
||||
<para>One of the areas that contains a considerable number of 2.0
|
||||
and 2.5 improvements is Spring's IoC container.</para>
|
||||
|
||||
<section id="new-in-2-ioc-scopes">
|
||||
<title>New bean scopes</title>
|
||||
|
||||
<para>Previous versions of Spring had IoC container level support for
|
||||
exactly two distinct bean scopes (singleton and prototype). Spring 2.0
|
||||
improves on this by not only providing a number of additional scopes
|
||||
depending on the environment in which Spring is being deployed (for
|
||||
example, request and session scoped beans in a web environment), but
|
||||
also by providing integration points so that Spring users can create
|
||||
their own scopes.</para>
|
||||
|
||||
<para>It should be noted that although the underlying (and internal)
|
||||
implementation for singleton- and prototype-scoped beans has been
|
||||
changed, this change is totally transparent to the end user... no
|
||||
existing configuration needs to change, and no existing configuration
|
||||
will break.</para>
|
||||
|
||||
<para>Both the new and the original scopes are detailed in the section
|
||||
entitled <xref linkend="beans-factory-scopes"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-ioc-configuration">
|
||||
<title>Easier XML configuration</title>
|
||||
|
||||
<para>Spring XML configuration is now even easier, thanks to the advent
|
||||
of the new XML configuration syntax based on XML Schema. If you want to
|
||||
take advantage of the new tags that Spring provides (and the Spring team
|
||||
certainly suggest that you do because they make configuration less
|
||||
verbose and easier to read), then do read the section entitled <xref
|
||||
linkend="xsd-config"/>.</para>
|
||||
|
||||
<para>On a related note, there is a new, updated DTD for Spring 2.0 that
|
||||
you may wish to reference if you cannot take advantage of the XML
|
||||
Schema-based configuration. The DOCTYPE declaration is included below
|
||||
for your convenience, but the interested reader should definitely read
|
||||
the <filename>'spring-beans-2.0.dtd'</filename> DTD included in the
|
||||
<filename class="directory">'dist/resources'</filename> directory of the
|
||||
Spring 2.5 distribution.</para>
|
||||
|
||||
<programlisting><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
|
||||
"http://www.springframework.org/dtd/spring-beans-2.0.dtd"></programlisting>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-ioc-custom-configuration">
|
||||
<title>Extensible XML authoring</title>
|
||||
|
||||
<para>Not only is XML configuration easier to write, it is now also
|
||||
extensible.</para>
|
||||
|
||||
<para>What 'extensible' means in this context is that you, as an
|
||||
application developer, or (more likely) as a third party framework or
|
||||
product vendor, can write custom tags that other developers can then
|
||||
plug into their own Spring configuration files. This allows you to have
|
||||
your own domain specific language (the term is used loosely here) of
|
||||
sorts be reflected in the specific configuration of your own
|
||||
components.</para>
|
||||
|
||||
<para>Implementing custom Spring tags may not be of interest to every
|
||||
single application developer or enterprise architect using Spring in
|
||||
their own projects. We expect third-party vendors to be highly
|
||||
interested in developing custom configuration tags for use in Spring
|
||||
configuration files.</para>
|
||||
|
||||
<para>The extensible configuration mechanism is documented in <xref
|
||||
linkend="extensible-xml"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-ioc-annotations">
|
||||
<title>Annotation-driven configuration</title>
|
||||
|
||||
<para>Spring 2.0 introduced support for various annotations for
|
||||
configuration purposes, such as <interfacename>@Transactional</interfacename>,
|
||||
<interfacename>@Required</interfacename> and <interfacename>@PersistenceContext</interfacename>
|
||||
/<interfacename>@PersistenceUnit</interfacename>.</para>
|
||||
|
||||
<para>Spring 2.5 introduces support for a complete set of configuration
|
||||
annotations: <interfacename>@Autowired</interfacename> in combination
|
||||
with support for the JSR-250 annotations <interfacename>@Resource</interfacename>,
|
||||
<interfacename>@PostConstruct</interfacename> and <interfacename>@PreDestroy</interfacename>
|
||||
.</para>
|
||||
|
||||
<para>Annotation-driven bean configuration is discussed in <xref
|
||||
linkend="beans-annotation-config"/>. Check out annotation support
|
||||
for Spring MVC as well: <xref linkend="new-in-2-web-annotations"/></para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-ioc-component-scanning">
|
||||
<title>Autodetecting components in the classpath</title>
|
||||
|
||||
<para>Spring 2.5 introduces support component scanning: autodetecting
|
||||
annotated components in the classpath. Typically, such component classes
|
||||
will be annotated with stereotypes such as <interfacename>@Component</interfacename>,
|
||||
<interfacename>@Repository</interfacename>, <interfacename>@Service</interfacename>,
|
||||
<interfacename>@Controller</interfacename>. Depending on the application
|
||||
context configuration, such component classes will be autodetected and
|
||||
turned into Spring bean definitions, not requiring explicit configuration
|
||||
for each such bean.</para>
|
||||
|
||||
<para>Annotation-driven bean configuration is discussed in <xref
|
||||
linkend="beans-stereotype-annotations"/>.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-aop">
|
||||
<title>Aspect Oriented Programming (AOP)</title>
|
||||
|
||||
<para>Spring 2.0 has a much improved AOP offering. The Spring AOP
|
||||
framework itself is markedly easier to configure in XML, and significantly
|
||||
less verbose as a result; and Spring 2.0 integrates with the AspectJ
|
||||
pointcut language and @AspectJ aspect declaration style. The chapter
|
||||
entitled <xref linkend="aop"/> is dedicated to describing this new
|
||||
support.</para>
|
||||
|
||||
<section id="new-in-2-aop-configuration">
|
||||
<title>Easier AOP XML configuration</title>
|
||||
|
||||
<para>Spring 2.0 introduces new schema support for defining aspects
|
||||
backed by regular Java objects. This support takes advantage of the
|
||||
AspectJ pointcut language and offers fully typed advice (i.e. no more
|
||||
casting and <literal>Object[]</literal> argument manipulation). Details
|
||||
of this support can be found in the section entitled <xref
|
||||
linkend="aop-schema"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-aop-aspectj">
|
||||
<title>Support for @AspectJ aspects</title>
|
||||
|
||||
<para>Spring 2.0 also supports aspects defined using the @AspectJ
|
||||
annotations. These aspects can be shared between AspectJ and Spring AOP,
|
||||
and require (honestly!) only some simple configuration. Said support for
|
||||
@AspectJ aspects is discussed in <xref
|
||||
linkend="aop-ataspectj"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-aop-bean-pointcuts">
|
||||
<title>Support for bean name pointcut element</title>
|
||||
|
||||
<para>Spring 2.5 introduces support for the <literal>bean(...)</literal>
|
||||
pointcut element, matching specific named beans according to Spring-defined
|
||||
bean names. See <xref linkend="aop-pointcuts-designators"/> for details.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-aop-load-time-weaving">
|
||||
<title>Support for AspectJ load-time weaving</title>
|
||||
|
||||
<para>Spring 2.5 introduces explicit support AspectJ load-time weaving,
|
||||
as alternative to the proxy-based AOP framework. The new
|
||||
<literal>context:load-time-weaver</literal> configuration element
|
||||
automatically activates AspectJ aspects as defined in AspectJ's
|
||||
<literal>META-INF/aop.xml</literal> descriptor, applying them to the
|
||||
current application context through registering a transformer with the
|
||||
underlying ClassLoader. Note that this only works in environments with
|
||||
class transformation support. Check out <xref linkend="aop-aj-ltw"/>
|
||||
for the capabilities and limitations.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-middle-tier">
|
||||
<title>The Middle Tier</title>
|
||||
|
||||
<section id="new-in-2-middle-tier-transaction-configuration">
|
||||
<title>Easier configuration of declarative transactions in XML</title>
|
||||
|
||||
<para>The way that transactions are configured in Spring 2.0 has been
|
||||
changed significantly. The previous 1.2.x style of configuration
|
||||
continues to be valid (and supported), but the new style is markedly
|
||||
less verbose and is the recommended style. Spring 2.0 also ships with an
|
||||
AspectJ aspects library that you can use to make pretty much any object
|
||||
transactional - even objects not created by the Spring IoC container.</para>
|
||||
|
||||
<para>Spring 2.5 supports convenient annotation-driven transaction
|
||||
management in combination with load-time weaving, through the use of
|
||||
<literal>context:load-time-weaver</literal> in combination with
|
||||
<literal>tx:annotation-driven mode="aspectj"</literal>.</para>
|
||||
|
||||
<para>The chapter entitled <xref linkend="transaction"/> contains all
|
||||
of the details.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-middle-tier-websphere">
|
||||
<title>Full WebSphere transaction management support</title>
|
||||
|
||||
<para>Spring 2.5 explicitly supports IBM's WebSphere Application Server,
|
||||
in particular with respect to WebSphere's transaction manager.
|
||||
Transaction suspension is now fully supported through the use of
|
||||
WebSphere's new <interfacename>UOWManager</interfacename> API, which
|
||||
is available on WAS 6.0.2.19+ and 6.0.1.9+.</para>
|
||||
|
||||
<para>So if you run a Spring-based application on the WebSphere
|
||||
Application Server, we highly recommend to use Spring 2.5's
|
||||
<classname>WebSphereUowTransactionManager</classname> as your
|
||||
<interfacename>PlatformTransactionManager</interfacename> of choice.
|
||||
This is also IBM's official recommendation.</para>
|
||||
|
||||
<para>For automatic detection of the underlying JTA-based transaction
|
||||
platform, consider the use of Spring 2.5's new
|
||||
<literal>tx:jta-transaction-manager</literal> configuration element.
|
||||
This will autodetect BEA WebLogic and IBM WebSphere, registering the
|
||||
appropriate <interfacename>PlatformTransactionManager</interfacename>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-middle-tier-jpa">
|
||||
<title>JPA</title>
|
||||
|
||||
<para>Spring 2.0 ships with a JPA abstraction layer that is similar in
|
||||
intent to Spring's JDBC abstraction layer in terms of scope and general
|
||||
usage patterns.</para>
|
||||
|
||||
<para>If you are interested in using a JPA-implementation as the
|
||||
backbone of your persistence layer, the section entitled <xref
|
||||
linkend="orm-jpa"/> is dedicated to detailing Spring's support and
|
||||
value-add in this area.</para>
|
||||
|
||||
<para>Spring 2.5 upgrades its OpenJPA support to OpenJPA 1.0,
|
||||
with support for advanced features such as savepoints.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-middle-tier-async-jms">
|
||||
<title>Asynchronous JMS</title>
|
||||
|
||||
<para>Prior to Spring 2.0, Spring's JMS offering was limited to sending
|
||||
messages and the <emphasis>synchronous</emphasis> receiving of messages.
|
||||
This functionality (encapsulated in the
|
||||
<classname>JmsTemplate</classname> class) is great, but it doesn't
|
||||
address the requirement for the <emphasis>asynchronous</emphasis>
|
||||
receiving of messages.</para>
|
||||
|
||||
<para>Spring 2.0 now ships with full support for the reception of
|
||||
messages in an asynchronous fashion, as detailed in the section entitled
|
||||
<xref linkend="jms-asynchronousMessageReception"/>.</para>
|
||||
|
||||
<para>As of Spring 2.5, the JCA style of setting up asynchronous
|
||||
message listeners is supported as well, through the
|
||||
<classname>GenericMessageEndpointManager</classname> facility.
|
||||
This is an alternative to the standard JMS listener facility, allowing
|
||||
closer integration with message brokers such as ActiveMQ and JORAM.
|
||||
See <xref linkend="jms-jca-message-endpoint-manager"/>.</para>
|
||||
|
||||
<para>Spring 2.5 also introduces an XML namespace for simplifying JMS
|
||||
configuration, offering concise configuration of a large numbers of
|
||||
listeners. This namespace supports both the standard JMS listener facility
|
||||
as well as the JCA setup style, with minimal changes in the configuration.
|
||||
See <xref linkend="jms-namespace"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-middle-tier-jdbc">
|
||||
<title>JDBC</title>
|
||||
|
||||
<para>There are some small (but nevertheless notable) new classes in the
|
||||
Spring Framework's JDBC support library. The first, <link
|
||||
linkend="jdbc-NamedParameterJdbcTemplate"><classname>NamedParameterJdbcTemplate</classname></link>,
|
||||
provides support for programming JDBC statements using named parameters
|
||||
(as opposed to programming JDBC statements using only classic
|
||||
placeholder (<literal>'?'</literal>) arguments.</para>
|
||||
|
||||
<para>Another of the new classes, the <link
|
||||
linkend="jdbc-SimpleJdbcTemplate"><classname>SimpleJdbcTemplate</classname></link>,
|
||||
is aimed at making using the <classname>JdbcTemplate</classname> even
|
||||
easier to use when you are developing against Java 5+ (Tiger).</para>
|
||||
|
||||
<para>Spring 2.5 significantly extends the functionality of
|
||||
<classname>SimpleJdbcTemplate</classname> and introduces
|
||||
<classname>SimpleJdbcCall</classname> and <classname>SimpleJdbcInsert</classname>
|
||||
operation objects.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web">
|
||||
<title>The Web Tier</title>
|
||||
|
||||
<para>The web tier support has been <emphasis>substantially</emphasis>
|
||||
improved and expanded in Spring 2.0, with annotation-based controllers
|
||||
introduced in Spring 2.5.</para>
|
||||
|
||||
<section id="new-in-2-web-convention">
|
||||
<title>Sensible defaulting in Spring MVC</title>
|
||||
|
||||
<para>For a lot of projects, sticking to established conventions and
|
||||
having reasonable defaults is just what the projects need... this theme
|
||||
of convention-over-configuration now has explicit support in Spring MVC.
|
||||
What this means is that if you establish a set of naming conventions for
|
||||
your <literal>Controllers</literal> and views, you can
|
||||
<emphasis>substantially</emphasis> cut down on the amount of XML
|
||||
configuration that is required to setup handler mappings, view
|
||||
resolvers, <classname>ModelAndView</classname> instances, etc. This is a
|
||||
great boon with regards to rapid prototyping, and can also lend a degree
|
||||
of (always good-to-have) consistency across a codebase.</para>
|
||||
|
||||
<para>Spring MVC's convention-over-configuration support is detailed in
|
||||
the section entitled <xref linkend="mvc-coc"/></para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-portlet">
|
||||
<title>Portlet framework</title>
|
||||
|
||||
<para>Spring 2.0 ships with a Portlet framework that is conceptually
|
||||
similar to the Spring MVC framework. Detailed coverage of the Spring
|
||||
Portlet framework can be found in the section entitled <xref
|
||||
linkend="portlet"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-annotations">
|
||||
<title>Annotation-based controllers</title>
|
||||
|
||||
<para>Spring 2.5 introduces an annotation-based programming model for MVC
|
||||
controllers, using annotations such as <interfacename>@RequestMapping</interfacename>,
|
||||
<interfacename>@RequestParam</interfacename>, <interfacename>@ModelAttribute</interfacename>,
|
||||
etc. This annotation support is available for both Servlet MVC and Portlet
|
||||
MVC. Controllers implemented in this style do not have to extend specific
|
||||
base classes or implement specific interfaces. Furthermore, they do not
|
||||
usually have direct dependencies on Servlet or Portlet API's, although
|
||||
they can easily get access to Servlet or Portlet facilities if desired.
|
||||
For further details, see <xref linkend="mvc-annotation"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-form-tags">
|
||||
<title>A form tag library for Spring MVC</title>
|
||||
|
||||
<para>A rich JSP tag library for Spring MVC was <emphasis>the</emphasis>
|
||||
JIRA issue that garnered the most votes from Spring users (by a wide
|
||||
margin).</para>
|
||||
|
||||
<para>Spring 2.0 ships with a full featured JSP tag library that makes
|
||||
the job of authoring JSP pages much easier when using Spring MVC; the
|
||||
Spring team is confident it will satisfy all of those developers who
|
||||
voted for the issue on JIRA. The new tag library is itself covered in
|
||||
the section entitled <xref linkend="view-jsp-formtaglib"/>, and a quick
|
||||
reference to all of the new tags can be found in the appendix entitled
|
||||
<xref linkend="spring-form.tld"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-tiles2">
|
||||
<title>Tiles 2 support</title>
|
||||
|
||||
<para>Spring 2.5 ships support for Tiles 2, the next generation of the
|
||||
popular Tiles templating framework. This supersedes Spring's former support
|
||||
for Tiles 1, as included in Struts 1.x. See <xref linkend="view-tiles"/>
|
||||
for details.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-jsf12">
|
||||
<title>JSF 1.2 support</title>
|
||||
|
||||
<para>Spring 2.5 supports JSF 1.2, providing a JSF 1.2 variant of Spring's
|
||||
<classname>DelegatingVariableResolver</classname> in the form of the new
|
||||
<classname>SpringBeanFacesELResolver</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-jaxws">
|
||||
<title>JAX-WS support</title>
|
||||
|
||||
<para>Spring 2.5 fully supports JAX-WS 2.0/2.1, as included in Java 6 and Java EE 5.
|
||||
JAX-WS is the successor of JAX-RPC, allowing access to WSDL/SOAP-based web
|
||||
services as well as JAX-WS style exposure of web services.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other">
|
||||
<title>Everything else</title>
|
||||
|
||||
<para>This final section outlines all of the other new and improved Spring
|
||||
2.0/2.5 features and functionality.</para>
|
||||
|
||||
<section id="new-in-2-other-dynamic-language-support">
|
||||
<title>Dynamic language support</title>
|
||||
|
||||
<para>Spring 2.0 introduced support for beans written in languages other
|
||||
than Java, with the currently supported dynamic languages being JRuby,
|
||||
Groovy and BeanShell. This dynamic language support is comprehensively
|
||||
detailed in the section entitled <xref linkend="dynamic-language"/>.</para>
|
||||
|
||||
<para>Spring 2.5 refines the dynamic languages support with autowiring
|
||||
and support for the recently released JRuby 1.0.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-testing">
|
||||
<title>Enhanced testing support</title>
|
||||
|
||||
<para>Spring 2.5 introduces the <emphasis>Spring TestContext
|
||||
Framework</emphasis> which provides annotation-driven unit and integration
|
||||
testing support that is agnostic of the actual testing framework in use.
|
||||
The same techniques and annotation-based configuration used in, for
|
||||
example, a JUnit 3.8 environment can also be applied to tests written with
|
||||
JUnit 4.4, TestNG, etc.</para>
|
||||
|
||||
<para>In addition to providing generic and extensible testing
|
||||
infrastructure, the <emphasis>Spring TestContext Framework</emphasis>
|
||||
provides out-of-the-box support for Spring-specific integration testing
|
||||
functionality such as <link linkend="testcontext-ctx-management">context
|
||||
management and caching</link>, <link
|
||||
linkend="testcontext-fixture-di">dependency injection of test
|
||||
fixtures</link>, and <link linkend="testcontext-tx">transactional test
|
||||
management</link> with default rollback semantics.</para>
|
||||
|
||||
<para>To discover how this new testing support can assist you with writing
|
||||
unit and integration tests, consult <xref linkend="testcontext-framework"/>
|
||||
of the revised testing chapter.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-jmx">
|
||||
<title>JMX support</title>
|
||||
|
||||
<para>The Spring Framework 2.0 has support for
|
||||
<literal>Notifications</literal>; it is also possible to exercise
|
||||
declarative control over the registration behavior of MBeans with an
|
||||
<literal>MBeanServer</literal>.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<xref linkend="jmx-notifications"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="jmx-exporting-registration-behavior"/>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Furthermore, Spring 2.5 provides a
|
||||
<link linkend="jmx-context-mbeanexport"><literal>context:mbean-export</literal></link>
|
||||
configuration element for convenient registration of annotated bean classes,
|
||||
detecting Spring's <interfacename>@ManagedResource</interfacename> annotation.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-jca">
|
||||
<title>Deploying a Spring application context as JCA adapter</title>
|
||||
|
||||
<para>Spring 2.5 supports the deployment of a Spring application context
|
||||
as JCA resource adapter, packaged as a JCA RAR file. This allows headless
|
||||
application modules to be deployed into J2EE servers, getting access to
|
||||
all the server's infrastructure e.g. for executing scheduled tasks,
|
||||
listening for incoming messages, etc.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-taskexecutor">
|
||||
<title>Task scheduling</title>
|
||||
|
||||
<para>Spring 2.0 offers an abstraction around the scheduling of tasks.
|
||||
For the interested developer, the section entitled <xref
|
||||
linkend="scheduling-task-executor"/> contains all of the
|
||||
details.</para>
|
||||
|
||||
<para>The <interfacename>TaskExecutor</interfacename> abstraction is used
|
||||
throughout the framework itself as well, e.g. for the asynchronous JMS support.
|
||||
In Spring 2.5, it is also used in the JCA environment support.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-java5">
|
||||
<title>Java 5 (Tiger) support</title>
|
||||
|
||||
<para>Find below pointers to documentation describing some of the new
|
||||
Java 5 support in Spring 2.0 and 2.5.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<xref linkend="beans-annotation-config"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="metadata-annotations-required"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="transaction-declarative-annotations"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="jdbc-SimpleJdbcTemplate"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="orm-jpa"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="aop-ataspectj"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="aop-atconfigurable"/>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating">
|
||||
<title>Migrating to Spring 2.5</title>
|
||||
|
||||
<para>This final section details issues that may arise during any
|
||||
migration from Spring 1.2/2.0 to Spring 2.5.</para>
|
||||
|
||||
<para>Upgrading to Spring 2.5 from a Spring 2.0.x application should
|
||||
simply be a matter of dropping the Spring 2.5 jar into the appropriate
|
||||
location in your application's directory structure. We highly recommend
|
||||
upgrading to Spring 2.5 from any Spring 2.0 application that runs on
|
||||
JDK 1.4.2 or higher, in particular when running on Java 5 or higher,
|
||||
leveraging the significant configuration conveniences and performance
|
||||
improvements that Spring 2.5 has to offer.</para>
|
||||
|
||||
<para>Whether an upgrade from Spring 1.2.x will be as seamless depends on
|
||||
how much of the Spring APIs you are using in your code. Spring 2.0
|
||||
removed pretty much all of the classes and methods previously marked
|
||||
as deprecated in the Spring 1.2.x codebase, so if you have been using
|
||||
such classes and methods, you will of course have to use alternative
|
||||
classes and methods (some of which are summarized below).</para>
|
||||
|
||||
<para>With regards to configuration, Spring 1.2.x style XML configuration
|
||||
is 100%, satisfaction-guaranteed compatible with the Spring 2.5 library.
|
||||
Of course if you are still using the Spring 1.2.x DTD, then you won't be
|
||||
able to take advantage of some of the new Spring 2.0 functionality (such
|
||||
as <link linkend="new-in-2-ioc-scopes">scopes</link> and <link
|
||||
linkend="new-in-2-aop-configuration">easier AOP</link> and <link
|
||||
linkend="new-in-2-middle-tier-transaction-configuration">transaction
|
||||
configuration</link>), but nothing will blow up.</para>
|
||||
|
||||
<para>The suggested migration strategy is to drop in the Spring 2.5 jar(s)
|
||||
to benefit from the improved code present in the release (bug fixes,
|
||||
optimizations, etc.). You can then, on an incremental basis, choose to
|
||||
start using the new Spring 2.5 features and configuration. For example,
|
||||
you could choose to start configuring just your aspects in the new Spring
|
||||
2 style; it is perfectly valid to have 90% of your configuration using
|
||||
the old-school Spring 1.2.x configuration (which references the 1.2.x
|
||||
DTD), and have the other 10% using the new Spring 2 configuration (which
|
||||
references the 2.0/2.5 DTD or XSD). Bear in mind that you are not forced to
|
||||
upgrade your XML configuration should you choose to drop in the Spring 2.5
|
||||
libraries.</para>
|
||||
|
||||
<section id="new-in-2-migrating-changes">
|
||||
<title>Changes</title>
|
||||
|
||||
<para>For a comprehensive list of changes, consult the
|
||||
<filename>'changelog.txt'</filename> file that is located in the top
|
||||
level directory of the Spring Framework distribution.</para>
|
||||
|
||||
<section id="new-in-2-migrating-jdk">
|
||||
<title>Supported JDK versions</title>
|
||||
|
||||
<para>As of Spring 2.5, support for JDK 1.3 has been removed,
|
||||
following Sun's official deprecation of JDK 1.3 in late 2006.
|
||||
If you haven't done so already, upgrade to JDK 1.4.2 or higher.</para>
|
||||
|
||||
<para>If you need to stick with an application server that only supports
|
||||
JDK 1.3, such as WebSphere 4.0 or 5.0, we recommend using the
|
||||
Spring Framework version 2.0.7/2.0.8 which still supports JDK 1.3.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-packaging">
|
||||
<title>Jar packaging in Spring 2.5</title>
|
||||
|
||||
<para>As of Spring 2.5, Spring Web MVC is no longer part of the
|
||||
<filename class="libraryfile">'spring.jar'</filename> file. Spring MVC
|
||||
can be found in <filename class="libraryfile">'spring-webmvc.jar'</filename>
|
||||
and <filename class="libraryfile">'spring-webmvc-portlet.jar'</filename>
|
||||
in the <literal>lib/modules</literal> directory of the distribution.
|
||||
Furthermore, the Struts 1.x support has been factored out into
|
||||
<filename class="libraryfile">'spring-webmvc-struts.jar'</filename>.</para>
|
||||
|
||||
<para><emphasis>Note: The commonly used Spring's <classname>DispatcherServlet</classname>
|
||||
is part of Spring's Web MVC framework.</emphasis> As a consequence,
|
||||
you need to add <filename class="libraryfile">'spring-webmvc.jar'</filename>
|
||||
(or <filename class="libraryfile">'spring-webmvc-portlet/struts.jar'</filename>)
|
||||
to a <filename class="libraryfile">'spring.jar'</filename> scenario,
|
||||
even if you are just using <classname>DispatcherServlet</classname>
|
||||
for remoting purposes (e.g. exporting Hessian or HTTP invoker services).</para>
|
||||
|
||||
<para>Spring 2.0's <filename class="libraryfile">'spring-jmx.jar'</filename>
|
||||
and <filename class="libraryfile">'spring-remoting.jar'</filename> have been
|
||||
merged into Spring 2.5's <filename class="libraryfile">'spring-context.jar'</filename>
|
||||
(for the JMX and non-HTTP remoting support) and partly into
|
||||
<filename class="libraryfile">'spring-web.jar'</filename>
|
||||
(for the HTTP remoting support).</para>
|
||||
|
||||
<para>Spring 2.0's <filename class="libraryfile">'spring-support.jar'</filename>
|
||||
has been renamed to <filename class="libraryfile">'spring-context-support.jar'</filename>,
|
||||
expressing the actual support relationship more closely.
|
||||
<filename class="libraryfile">'spring-portlet.jar'</filename> has been
|
||||
renamed to <filename class="libraryfile">'spring-webmvc-portlet.jar'</filename>,
|
||||
since it is technically a submodule of Spring's Web MVC framework.
|
||||
Analogously, <filename class="libraryfile">'spring-struts.jar'</filename>
|
||||
has been renamed to <filename class="libraryfile">'spring-webmvc-struts.jar'</filename>.
|
||||
</para>
|
||||
|
||||
<para>Spring 2.0's <filename class="libraryfile">'spring-jdo.jar'</filename>,
|
||||
<filename class="libraryfile">'spring-jpa.jar'</filename>,
|
||||
<filename class="libraryfile">'spring-hibernate3.jar'</filename>,
|
||||
<filename class="libraryfile">'spring-toplink.jar'</filename>
|
||||
and <filename class="libraryfile">'spring-ibatis.jar'</filename>
|
||||
have been combined into Spring 2.5's coarse-granular
|
||||
<filename class="libraryfile">'spring-orm.jar'</filename>.</para>
|
||||
|
||||
<para>Spring 2.5's <filename class="libraryfile">'spring-test.jar'</filename>
|
||||
supersedes the previous <filename class="libraryfile">'spring-mock.jar'</filename>,
|
||||
indicating the stronger focus on the test context framework.
|
||||
Note that <filename class="libraryfile">'spring-test.jar'</filename>
|
||||
contains everything <filename class="libraryfile">'spring-mock.jar'</filename>
|
||||
contained in previous Spring versions; hence it can be used as a
|
||||
straightforward replacement for unit and integration testing purposes.</para>
|
||||
|
||||
<para>Spring 2.5's <filename class="libraryfile">'spring-tx.jar'</filename>
|
||||
supersedes the previous <filename class="libraryfile">'spring-dao.jar'</filename>
|
||||
and <filename class="libraryfile">'spring-jca.jar'</filename> files,
|
||||
indicating the stronger focus on the transaction framework.</para>
|
||||
|
||||
<para>Spring 2.5 ships its framework jars as OSGi-compliant bundles
|
||||
out of the box. This facilitates use of Spring in OSGi environments,
|
||||
not requiring custom packaging anymore.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-xml-configuration">
|
||||
<title>XML configuration</title>
|
||||
|
||||
<para>Spring 2.0 ships with XSDs that describe Spring's XML metadata
|
||||
format in a much richer fashion than the DTD that shipped with
|
||||
previous versions. The old DTD is still fully supported, but if
|
||||
possible you are encouraged to reference the XSD files at the top of
|
||||
your bean definition files.</para>
|
||||
|
||||
<para>One thing that has changed in a (somewhat) breaking fashion is
|
||||
the way that bean scopes are defined. If you are using the Spring 1.2
|
||||
DTD you can continue to use the <literal>'singleton'</literal>
|
||||
attribute. You can however choose to <link
|
||||
linkend="new-in-2-ioc-configuration">reference the new Spring 2.0
|
||||
DTD</link> which does not permit the use of the
|
||||
<literal>'singleton'</literal> attribute, but rather uses the
|
||||
<literal>'scope'</literal> attribute to define the bean lifecycle
|
||||
scope.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-deprecated">
|
||||
<title>Deprecated classes and methods</title>
|
||||
|
||||
<para>A number of classes and methods that previously were marked as
|
||||
<literal>@deprecated</literal> have been removed from the Spring 2.0
|
||||
codebase. The Spring team decided that the 2.0 release marked a fresh
|
||||
start of sorts, and that any deprecated 'cruft' was better excised now
|
||||
instead of continuing to haunt the codebase for the foreseeable
|
||||
future.</para>
|
||||
|
||||
<para>As mentioned previously, for a comprehensive list of changes,
|
||||
consult the <filename>'changelog.txt'</filename> file that is located
|
||||
in the top level directory of the Spring Framework distribution.</para>
|
||||
|
||||
<para>The following classes/interfaces have been removed as of Spring
|
||||
2.0:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><interfacename>ResultReader</interfacename> : Use the
|
||||
<interfacename>RowMapper</interfacename> interface instead.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>BeanFactoryBootstrap</classname> : Consider using
|
||||
a <interfacename>BeanFactoryLocator</interfacename> or a custom
|
||||
bootstrap class instead.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-ojb">
|
||||
<title>Apache OJB</title>
|
||||
|
||||
<para>As of Spring 2.0, support for Apache OJB was <emphasis>totally
|
||||
removed</emphasis> from the main Spring source tree. The Apache OJB
|
||||
integration library is still available, but can be found in its new
|
||||
home in the <ulink url="https://springmodules.dev.java.net/">Spring
|
||||
Modules project</ulink>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-ibatis">
|
||||
<title>iBATIS</title>
|
||||
|
||||
<para>Please note that support for iBATIS SQL Maps 1.3 has been removed.
|
||||
If you haven't done so already, upgrade to iBATIS SQL Maps 2.3.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-hibernate">
|
||||
<title>Hibernate</title>
|
||||
|
||||
<para>As of Spring 2.5, support for Hibernate 2.1 and Hibernate 3.0
|
||||
has been removed. If you haven't done so already, upgrade to
|
||||
Hibernate 3.1 or higher.</para>
|
||||
|
||||
<para>If you need to stick with Hibernate 2.1 or 3.0 for the time
|
||||
being, we recommend to keep using the Spring Framework version
|
||||
2.0.7/2.0.8 which still supports those versions of Hibernate.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-jdo">
|
||||
<title>JDO</title>
|
||||
|
||||
<para>As of Spring 2.5, support for JDO 1.0 has been removed.
|
||||
If you haven't done so already, upgrade to JDO 2.0 or higher.</para>
|
||||
|
||||
<para>If you need to stick with JDO 1.0 for the time being,
|
||||
we recommend to keep using the Spring Framework version
|
||||
2.0.7/2.0.8 which still supports that version of JDO.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-UrlFilenameViewController">
|
||||
<title><classname>UrlFilenameViewController</classname></title>
|
||||
|
||||
<para>Since Spring 2.0, the view name that is determined by the
|
||||
<classname>UrlFilenameViewController</classname> now takes into
|
||||
account the nested path of the request. This is a breaking change
|
||||
from the original contract of the
|
||||
<classname>UrlFilenameViewController</classname>, and means that if
|
||||
you are upgrading from Spring 1.x to Spring 2.x and you are using this
|
||||
class you <emphasis>might</emphasis> have to change your Spring Web
|
||||
MVC configuration slightly. Refer to the class level Javadocs of the
|
||||
<classname>UrlFilenameViewController</classname> to see examples of
|
||||
the new contract for view name determination.</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-applications">
|
||||
<title>Updated sample applications</title>
|
||||
|
||||
<para>A number of the sample applications have also been updated to
|
||||
showcase the new and improved features of Spring 2.0. So do take the time
|
||||
to investigate them. The aforementioned sample applications can be found
|
||||
in the <filename class="directory">'samples'</filename> directory of the
|
||||
full Spring distribution
|
||||
(<filename>'spring-with-dependencies.[zip|tar.gz]'</filename>).</para>
|
||||
|
||||
<para>Spring 2.5 features revised versions of the PetClinic and PetPortal sample
|
||||
applications, reengineered from the ground up for leveraging Spring 2.5's
|
||||
annotation configuration features. It also uses Java 5 autoboxing, generics,
|
||||
varargs and the enhanced for loop. A Java 5 or 6 SDK is now required to build and
|
||||
run the sample. Check out PetClinic and PetPortal to get an impression of what
|
||||
Spring 2.5 has to offer!</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-documentation">
|
||||
<title>Improved documentation</title>
|
||||
|
||||
<para>The Spring reference documentation has also substantially been
|
||||
updated to reflect all of the above features new in Spring 2.0 and 2.5.
|
||||
While every effort has been made to ensure that there are no errors in this
|
||||
documentation, some errors may nevertheless have crept in. If you do spot
|
||||
any typos or even more serious errors, and you can spare a few cycles
|
||||
during lunch, please do bring the error to the attention of the Spring
|
||||
team by <ulink
|
||||
url="http://opensource.atlassian.com/projects/spring/">raising an
|
||||
issue</ulink>.</para>
|
||||
|
||||
<para>Special thanks to Arthur Loder for his tireless proofreading of the
|
||||
Spring Framework reference documentation and JavaDocs.</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="new-in-2">
|
||||
<title>What's new in Spring 3.0?</title>
|
||||
|
||||
<section id="new-in-3-intro">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>*** WORK IN PROGRESS ***</para>
|
||||
|
||||
<para>If you have been using the Spring Framework for some time, you will
|
||||
be aware that Spring has undergone two major revisions: Spring 2.0,
|
||||
released in October 2006, and Spring 2.5, released in November 2007.</para>
|
||||
|
||||
<sidebar id="new-in-3-intro-java">
|
||||
<title>Java SE and Java EE Support</title>
|
||||
|
||||
<para>The Spring Framework is now based on Java 5 and Java 6 is fully supported.</para>
|
||||
|
||||
<para>Furthermore, Spring is compatible with J2EE 1.4 and Java EE 5,
|
||||
while at the same time introducing dedicated support for Java EE 6.</para>
|
||||
</sidebar>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="new-in-3-other-documentation">
|
||||
<title>Improved documentation</title>
|
||||
|
||||
<para>The Spring reference documentation has also substantially been
|
||||
updated to reflect all of the changes and new features for Spring 3.0.
|
||||
While every effort has been made to ensure that there are no errors in this
|
||||
documentation, some errors may nevertheless have crept in. If you do spot
|
||||
any typos or even more serious errors, and you can spare a few cycles
|
||||
during lunch, please do bring the error to the attention of the Spring
|
||||
team by <ulink
|
||||
url="http://jira.springframework.org/">raising an
|
||||
issue</ulink>.</para>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<sidebar id="background-ioc">
|
||||
<title>Background</title>
|
||||
|
||||
<para>In early 2004, Martin Fowler asked the readers of his site: when
|
||||
talking about Inversion of Control: <quote><emphasis>the question is, what
|
||||
aspect of control are [they] inverting?</emphasis></quote>. Fowler then
|
||||
suggested renaming the principle (or at least giving it a more
|
||||
self-explanatory name), and started to use the term <firstterm>Dependency
|
||||
Injection</firstterm>. His article then continued to explain the ideas
|
||||
underpinning the Inversion of Control (<acronym>IoC</acronym>) and
|
||||
Dependency Injection (<acronym>DI</acronym>) principle.</para>
|
||||
|
||||
<para>If you need a decent insight into IoC and DI, please do refer to
|
||||
said article : <ulink
|
||||
url="http://martinfowler.com/articles/injection.html">http://martinfowler.com/articles/injection.html</ulink>.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>Java applications (a loose term which runs the gamut from constrained
|
||||
applets to full-fledged n-tier server-side enterprise applications)
|
||||
typically are composed of a number of objects that collaborate with one
|
||||
another to form the application proper. The objects in an application can
|
||||
thus be said to have <emphasis>dependencies</emphasis> between
|
||||
themselves.</para>
|
||||
|
||||
<para>The Java language and platform provides a wealth of functionality for
|
||||
architecting and building applications, ranging all the way from the very
|
||||
basic building blocks of primitive types and classes (and the means to
|
||||
define new classes), to rich full-featured application servers and web
|
||||
frameworks. One area that is decidedly conspicuous by its absence is any
|
||||
means of taking the basic building blocks and composing them into a coherent
|
||||
whole; this area has typically been left to the purvey of the architects and
|
||||
developers tasked with building an application (or applications). Now to be
|
||||
fair, there are a number of design patterns devoted to the business of
|
||||
composing the various classes and object instances that makeup an
|
||||
all-singing, all-dancing application. Design patterns such as
|
||||
<firstterm>Factory</firstterm>, <firstterm>Abstract Factory</firstterm>,
|
||||
<firstterm>Builder</firstterm>, <firstterm>Decorator</firstterm>, and
|
||||
<firstterm>Service Locator</firstterm> (to name but a few) have widespread
|
||||
recognition and acceptance within the software development industry
|
||||
(presumably that is why these patterns have been formalized as patterns in
|
||||
the first place). This is all very well, but these patterns are just that:
|
||||
best practices given a name, typically together with a description of what
|
||||
the pattern does, where the pattern is typically best applied, the problems
|
||||
that the application of the pattern addresses, and so forth. Notice that the
|
||||
last paragraph used the phrase <quote>... a <emphasis>description</emphasis>
|
||||
of what the pattern does...</quote>; pattern books and wikis are typically
|
||||
listings of such formalized best practice that you can certainly take away,
|
||||
mull over, and then <emphasis>implement yourself</emphasis> in your
|
||||
application.</para>
|
||||
|
||||
<para>The IoC component of the Spring Framework addresses the enterprise
|
||||
concern of taking the classes, objects, and services that are to compose an
|
||||
application, by providing a formalized means of composing these various
|
||||
disparate components into a fully working application ready for use. The
|
||||
Spring Framework takes best practices that have been proven over the years
|
||||
in numerous applications and formalized as design patterns, and actually
|
||||
codifies these patterns as first class objects that you as an architect and
|
||||
developer can take away and integrate into your own application(s). This is
|
||||
a <firstterm>Very Good Thing Indeed</firstterm> as attested to by the
|
||||
numerous organizations and institutions that have used the Spring Framework
|
||||
to engineer robust, <emphasis>maintainable</emphasis> applications.</para>
|
||||
|
||||
<section id="introduction-overview">
|
||||
<title>Overview</title>
|
||||
|
||||
<para>The Spring Framework contains a lot of features, which are
|
||||
well-organized in six modules shown in the diagram below. This chapter
|
||||
discusses each of the modules in turn.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="left" fileref="images/spring-overview.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/spring-overview.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Overview of the Spring Framework</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>The <link
|
||||
linkend="beans-introduction"><emphasis>Core</emphasis></link> package is
|
||||
the most fundamental part of the framework and provides the IoC and
|
||||
Dependency Injection features. The basic concept here is the
|
||||
<classname>BeanFactory</classname>, which provides a sophisticated
|
||||
implementation of the factory pattern which removes the need for
|
||||
programmatic singletons and allows you to decouple the configuration and
|
||||
specification of dependencies from your actual program logic.</para>
|
||||
|
||||
<para>The <link
|
||||
linkend="context-introduction"><emphasis>Context</emphasis></link> package
|
||||
build on the solid base provided by the <link
|
||||
linkend="beans-introduction"><emphasis>Core</emphasis></link> package: it
|
||||
provides a way to access objects in a framework-style manner in a fashion
|
||||
somewhat reminiscent of a JNDI-registry. The context package inherits its
|
||||
features from the beans package and adds support for internationalization
|
||||
(I18N) (using for example resource bundles), event-propagation,
|
||||
resource-loading, and the transparent creation of contexts by, for
|
||||
example, a servlet container.</para>
|
||||
|
||||
<para>The <link linkend="dao-introduction"><emphasis>DAO</emphasis></link>
|
||||
package provides a JDBC-abstraction layer that removes the need to do
|
||||
tedious JDBC coding and parsing of database-vendor specific error codes.
|
||||
Also, the <link linkend="jdbc-introduction">JDBC</link> package provides a
|
||||
way to do programmatic as well as declarative transaction management, not
|
||||
only for classes implementing special interfaces, but for <emphasis>all
|
||||
your POJOs (plain old Java objects)</emphasis>.</para>
|
||||
|
||||
<para>The <link linkend="orm-introduction"><emphasis>ORM</emphasis></link>
|
||||
package provides integration layers for popular object-relational mapping
|
||||
APIs, including <link linkend="orm-jpa">JPA</link>, <link
|
||||
linkend="orm-jdo">JDO</link>, <link
|
||||
linkend="orm-hibernate">Hibernate</link>, and <link
|
||||
linkend="orm-ibatis">iBatis</link>. Using the ORM package you can use all
|
||||
those O/R-mappers in combination with all the other features Spring
|
||||
offers, such as the simple declarative transaction management feature
|
||||
mentioned previously.</para>
|
||||
|
||||
<para>Spring's <link
|
||||
linkend="aop-introduction"><emphasis>AOP</emphasis></link> package
|
||||
provides an <emphasis>AOP Alliance</emphasis>-compliant aspect-oriented
|
||||
programming implementation allowing you to define, for example,
|
||||
method-interceptors and pointcuts to cleanly decouple code implementing
|
||||
functionality that should logically speaking be separated. Using
|
||||
source-level metadata functionality you can also incorporate all kinds of
|
||||
behavioral information into your code, in a manner similar to that of .NET
|
||||
attributes.</para>
|
||||
|
||||
<para>Spring's <emphasis>Web</emphasis> package provides basic
|
||||
web-oriented integration features, such as multipart file-upload
|
||||
functionality, the initialization of the IoC container using servlet
|
||||
listeners and a web-oriented application context. When using Spring
|
||||
together with WebWork or Struts, this is the package to integrate
|
||||
with.</para>
|
||||
|
||||
<para>Spring's <link
|
||||
linkend="mvc-introduction"><emphasis>MVC</emphasis></link> package
|
||||
provides a Model-View-Controller (MVC) implementation for
|
||||
web-applications. Spring's MVC framework is not just any old
|
||||
implementation; it provides a <emphasis>clean</emphasis> separation
|
||||
between domain model code and web forms, and allows you to use all the
|
||||
other features of the Spring Framework.</para>
|
||||
</section>
|
||||
|
||||
<section id="overview-usagescenarios">
|
||||
<title>Usage scenarios</title>
|
||||
|
||||
<para>With the building blocks described above you can use Spring in all
|
||||
sorts of scenarios, from applets up to fully-fledged enterprise
|
||||
applications using Spring's transaction management functionality and web
|
||||
framework integration.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/full.png" format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/full.gif" format="GIF" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Typical full-fledged Spring web
|
||||
application</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>By using Spring's <link
|
||||
linkend="transaction-declarative">declarative transaction management
|
||||
features</link> the web application is fully transactional, just as it
|
||||
would be when using container managed transactions as provided by
|
||||
Enterprise JavaBeans. All your custom business logic can be implemented
|
||||
using simple POJOs, managed by Spring's IoC container. Additional services
|
||||
include support for sending email, and validation that is independent of
|
||||
the web layer enabling you to choose where to execute validation rules.
|
||||
Spring's ORM support is integrated with JPA, Hibernate, JDO and iBatis;
|
||||
for example, when using Hibernate, you can continue to use your existing
|
||||
mapping files and standard Hibernate
|
||||
<interfacename>SessionFactory</interfacename> configuration. Form
|
||||
controllers seamlessly integrate the web-layer with the domain model,
|
||||
removing the need for <classname>ActionForms</classname> or other classes
|
||||
that transform HTTP parameters to values for your domain model.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/thirdparty-web.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/thirdparty-web.gif"
|
||||
format="GIF" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Spring middle-tier using a third-party web
|
||||
framework</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>Sometimes the current circumstances do not allow you to completely
|
||||
switch to a different framework. The Spring Framework does
|
||||
<emphasis>not</emphasis> force you to use everything within it; it is not
|
||||
an <emphasis>all-or-nothing</emphasis> solution. Existing front-ends built
|
||||
using WebWork, Struts, Tapestry, or other UI frameworks can be integrated
|
||||
perfectly well with a Spring-based middle-tier, allowing you to use the
|
||||
transaction features that Spring offers. The only thing you need to do is
|
||||
wire up your business logic using an
|
||||
<classname>ApplicationContext</classname> and integrate your web layer
|
||||
using a <classname>WebApplicationContext</classname>.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/remoting.png" format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/remoting.gif" format="GIF" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Remoting usage scenario</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>When you need to access existing code via web services, you can use
|
||||
Spring's <literal>Hessian-</literal>, <literal>Burlap-</literal>,
|
||||
<literal>Rmi-</literal> or <classname>JaxRpcProxyFactory</classname>
|
||||
classes. Enabling remote access to existing applications suddenly is not
|
||||
that hard anymore.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/ejb.png" format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/ejb.gif" format="GIF" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>EJBs - Wrapping existing POJOs</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>The Spring Framework also provides an <link linkend="ejb">access-
|
||||
and abstraction- layer</link> for Enterprise JavaBeans, enabling you to
|
||||
reuse your existing POJOs and wrap them in Stateless Session Beans, for
|
||||
use in scalable, failsafe web applications that might need declarative
|
||||
security.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<preface id="preface">
|
||||
<title>Preface</title>
|
||||
|
||||
<para>Developing software applications is hard enough even with good tools
|
||||
and technologies. Implementing applications using platforms which promise
|
||||
everything but turn out to be heavy-weight, hard to control and not very
|
||||
efficient during the development cycle makes it even harder. Spring provides
|
||||
a light-weight solution for building enterprise-ready applications, while
|
||||
still supporting the possibility of using declarative transaction
|
||||
management, remote access to your logic using RMI or web services, and
|
||||
various options for persisting your data to a database. Spring provides a
|
||||
full-featured <link linkend="mvc-introduction">MVC framework</link>, and
|
||||
transparent ways of integrating <link linkend="aop-introduction">AOP</link>
|
||||
into your software.</para>
|
||||
|
||||
<para>Spring could potentially be a one-stop-shop for all your enterprise
|
||||
applications; however, Spring is modular, allowing you to use just those
|
||||
parts of it that you need, without having to bring in the rest. You can use
|
||||
the IoC container, with Struts on top, but you could also choose to use just
|
||||
the <link linkend="orm-hibernate">Hibernate integration code</link> or the
|
||||
<link linkend="jdbc-introduction">JDBC abstraction layer</link>. Spring has
|
||||
been (and continues to be) designed to be non-intrusive, meaning
|
||||
dependencies on the framework itself are generally none (or absolutely
|
||||
minimal, depending on the area of use).</para>
|
||||
|
||||
<para>This document provides a reference guide to Spring's features. Since
|
||||
this document is still to be considered very much work-in-progress, if you
|
||||
have any requests or comments, please post them on the user mailing list or
|
||||
on the support forums at <ulink
|
||||
url="http://forum.springframework.org/" />.</para>
|
||||
|
||||
<para>Before we go on, a few words of gratitude are due to Christian Bauer
|
||||
(of the <ulink url="http://www.hibernate.org/">Hibernate</ulink> team), who
|
||||
prepared and adapted the DocBook-XSL software in order to be able to create
|
||||
Hibernate's reference guide, thus also allowing us to create this one. Also
|
||||
thanks to Russell Healy for doing an extensive and valuable review of some
|
||||
of the material.</para>
|
||||
</preface>
|
||||
|
|
@ -0,0 +1,739 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="resources">
|
||||
<title>Resources</title>
|
||||
|
||||
<section id="resources-introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>Java's standard <classname>java.net.URL</classname> class and
|
||||
standard handlers for various URL prefixes unfortunately are not quite
|
||||
adequate enough for all access to low-level resources. For example,
|
||||
there is no standardized <classname>URL</classname> implementation
|
||||
that may be used to access a resource that needs to be obtained from
|
||||
the classpath, or relative to a
|
||||
<interfacename>ServletContext</interfacename>. While it is possible
|
||||
to register new handlers for specialized <classname>URL</classname>
|
||||
prefixes (similar to existing handlers for prefixes such as
|
||||
<literal>http:</literal>), this is generally quite complicated, and the
|
||||
<classname>URL</classname> interface still lacks some desirable
|
||||
functionality, such as a method to check for the existence of the
|
||||
resource being pointed to.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-resource">
|
||||
<title>The <interfacename>Resource</interfacename> interface</title>
|
||||
|
||||
<para>Spring's <interfacename>Resource</interfacename> interface is meant
|
||||
to be a more capable interface for abstracting access to low-level
|
||||
resources.</para>
|
||||
|
||||
<programlisting><![CDATA[public interface Resource extends InputStreamSource {
|
||||
|
||||
boolean exists();
|
||||
|
||||
boolean isOpen();
|
||||
|
||||
URL getURL() throws IOException;
|
||||
|
||||
File getFile() throws IOException;
|
||||
|
||||
Resource createRelative(String relativePath) throws IOException;
|
||||
|
||||
String getFilename();
|
||||
|
||||
String getDescription();
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[public interface InputStreamSource {
|
||||
|
||||
InputStream getInputStream() throws IOException;
|
||||
}]]></programlisting>
|
||||
|
||||
<para>Some of the most important methods from the
|
||||
<interfacename>Resource</interfacename> interface are:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><methodname>getInputStream()</methodname>: locates and opens the
|
||||
resource, returning an <classname>InputStream</classname> for reading
|
||||
from the resource. It is expected that each invocation returns a
|
||||
fresh <classname>InputStream</classname>. It is the responsibility of
|
||||
the caller to close the stream.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>exists()</methodname>: returns a
|
||||
<literal>boolean</literal> indicating whether this resource actually
|
||||
exists in physical form.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>isOpen()</methodname>: returns a
|
||||
<literal>boolean</literal> indicating whether this resource represents
|
||||
a handle with an open stream. If <literal>true</literal>, the
|
||||
<classname>InputStream</classname> cannot be read multiple times, and
|
||||
must be read once only and then closed to avoid resource leaks. Will
|
||||
be <literal>false</literal> for all usual resource implementations,
|
||||
with the exception of
|
||||
<classname>InputStreamResource</classname>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>getDescription()</methodname>: returns a description
|
||||
for this resource, to be used for error output when working with the
|
||||
resource. This is often the fully qualified file name or the actual
|
||||
URL of the resource.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Other methods allow you to obtain an actual
|
||||
<classname>URL</classname> or <classname>File</classname> object
|
||||
representing the resource (if the underlying implementation is compatible,
|
||||
and supports that functionality).</para>
|
||||
|
||||
<para>The <interfacename>Resource</interfacename> abstraction is used
|
||||
extensively in Spring itself, as an argument type in many method
|
||||
signatures when a resource is needed. Other methods in some Spring APIs
|
||||
(such as the constructors to various
|
||||
<interfacename>ApplicationContext</interfacename> implementations), take a
|
||||
<classname>String</classname> which in unadorned or simple form is used to
|
||||
create a <interfacename>Resource</interfacename> appropriate to that
|
||||
context implementation, or via special prefixes on the
|
||||
<classname>String</classname> path, allow the caller to specify that a
|
||||
specific <interfacename>Resource</interfacename> implementation must be
|
||||
created and used.</para>
|
||||
|
||||
<para>While the <interfacename>Resource</interfacename> interface is used
|
||||
a lot with Spring and by Spring, it's actually very useful to use as a
|
||||
general utility class by itself in your own code, for access to resources,
|
||||
even when your code doesn't know or care about any other parts of Spring.
|
||||
While this couples your code to Spring, it really only couples it to this
|
||||
small set of utility classes, which are serving as a more capable
|
||||
replacement for <classname>URL</classname>, and can be considered
|
||||
equivalent to any other library you would use for this purpose.</para>
|
||||
|
||||
<para>It is important to note that the
|
||||
<interfacename>Resource</interfacename> abstraction does not replace
|
||||
functionality: it wraps it where possible. For example, a
|
||||
<classname>UrlResource</classname> wraps a URL, and uses the wrapped
|
||||
<classname>URL</classname> to do its work.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations">
|
||||
<title>Built-in <interfacename>Resource</interfacename> implementations</title>
|
||||
|
||||
<para>There are a number of <interfacename>Resource</interfacename>
|
||||
implementations that come supplied straight out of the box in
|
||||
Spring:</para>
|
||||
|
||||
<section id="resources-implementations-urlresource">
|
||||
<title><classname>UrlResource</classname></title>
|
||||
|
||||
<para>The <classname>UrlResource</classname> wraps a
|
||||
<classname>java.net.URL</classname>, and may be used to access any
|
||||
object that is normally accessible via a URL, such as files, an HTTP
|
||||
target, an FTP target, etc. All URLs have a standardized
|
||||
<classname>String</classname> representation, such that appropriate
|
||||
standardized prefixes are used to indicate one URL type from another.
|
||||
This includes <literal>file:</literal> for accessing filesystem paths,
|
||||
<literal>http:</literal> for accessing resources via the HTTP protocol,
|
||||
<literal>ftp:</literal> for accessing resources via FTP, etc.</para>
|
||||
|
||||
<para>A <classname>UrlResource</classname> is created by Java code
|
||||
explicitly using the <classname>UrlResource</classname> constructor, but
|
||||
will often be created implicitly when you call an API method which takes
|
||||
a <classname>String</classname> argument which is meant to represent a
|
||||
path. For the latter case, a JavaBeans
|
||||
<interfacename>PropertyEditor</interfacename> will ultimately decide
|
||||
which type of <interfacename>Resource</interfacename> to create. If the
|
||||
path string contains a few well-known (to it, that is) prefixes such as
|
||||
<literal>classpath:</literal>, it will create an appropriate specialized
|
||||
<interfacename>Resource</interfacename> for that prefix. However, if it
|
||||
doesn't recognize the prefix, it will assume the this is just a standard
|
||||
URL string, and will create a <classname>UrlResource</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-classpathresource">
|
||||
<title><classname>ClassPathResource</classname></title>
|
||||
|
||||
<para>This class represents a resource which should be obtained from the
|
||||
classpath. This uses either the thread context class loader, a given
|
||||
class loader, or a given class for loading resources.</para>
|
||||
|
||||
<para>This <interfacename>Resource</interfacename> implementation
|
||||
supports resolution as <classname>java.io.File</classname> if the class
|
||||
path resource resides in the file system, but not for classpath
|
||||
resources which reside in a jar and have not been expanded (by the
|
||||
servlet engine, or whatever the environment is) to the filesystem. To
|
||||
address this the various <interfacename>Resource</interfacename>
|
||||
implementations always support resolution as a
|
||||
<classname>java.net.URL</classname>.</para>
|
||||
|
||||
<para>A <classname>ClassPathResource</classname> is created by Java code
|
||||
explicitly using the <classname>ClassPathResource</classname>
|
||||
constructor, but will often be created implicitly when you call an API
|
||||
method which takes a <classname>String</classname> argument which is
|
||||
meant to represent a path. For the latter case, a JavaBeans
|
||||
<interfacename>PropertyEditor</interfacename> will recognize the special
|
||||
prefix <literal>classpath:</literal>on the string path, and create a
|
||||
<classname>ClassPathResource</classname> in that case.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-filesystemresource">
|
||||
<title><classname>FileSystemResource</classname></title>
|
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation
|
||||
for <classname>java.io.File</classname> handles. It obviously supports
|
||||
resolution as a <classname>File</classname>, and as a
|
||||
<classname>URL</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-servletcontextresource">
|
||||
<title><classname>ServletContextResource</classname></title>
|
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation
|
||||
for <interfacename>ServletContext</interfacename> resources,
|
||||
interpreting relative paths within the relevant web application's root
|
||||
directory.</para>
|
||||
|
||||
<para>This always supports stream access and URL access, but only allows
|
||||
<classname>java.io.File</classname> access when the web application
|
||||
archive is expanded and the resource is physically on the filesystem.
|
||||
Whether or not it's expanded and on the filesystem like this, or
|
||||
accessed directly from the JAR or somewhere else like a DB (it's
|
||||
conceivable) is actually dependent on the Servlet container.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-inputstreamresource">
|
||||
<title><classname>InputStreamResource</classname></title>
|
||||
|
||||
<para>A <interfacename>Resource</interfacename> implementation for a
|
||||
given <interfacename>InputStream</interfacename>. This should only be
|
||||
used if no specific <interfacename>Resource</interfacename>
|
||||
implementation is applicable. In particular, prefer
|
||||
<classname>ByteArrayResource</classname> or any of the file-based
|
||||
<interfacename>Resource</interfacename> implementations where
|
||||
possible.</para>
|
||||
|
||||
<para>In contrast to other <interfacename>Resource</interfacename>
|
||||
implementations, this is a descriptor for an
|
||||
<emphasis>already</emphasis> opened resource - therefore returning
|
||||
<literal>true</literal> from <methodname>isOpen()</methodname>. Do not
|
||||
use it if you need to keep the resource descriptor somewhere, or if you
|
||||
need to read a stream multiple times.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-bytearrayresource">
|
||||
<title><classname>ByteArrayResource</classname></title>
|
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation
|
||||
for a given byte array. It creates a
|
||||
<classname>ByteArrayInputStream</classname> for the given byte
|
||||
array.</para>
|
||||
|
||||
<para>It's useful for loading content from any given byte array, without
|
||||
having to resort to a single-use
|
||||
<classname>InputStreamResource</classname>.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-resourceloader">
|
||||
<title>The <interfacename>ResourceLoader</interfacename></title>
|
||||
|
||||
<para>The <interfacename>ResourceLoader</interfacename> interface is meant
|
||||
to be implemented by objects that can return (i.e. load)
|
||||
<interfacename>Resource</interfacename> instances.</para>
|
||||
|
||||
<programlisting>public interface ResourceLoader {
|
||||
Resource getResource(String location);
|
||||
}</programlisting>
|
||||
|
||||
<para>All application contexts implement the
|
||||
<interfacename>ResourceLoader</interfacename> interface, and therefore all
|
||||
application contexts may be used to obtain
|
||||
<interfacename>Resource</interfacename> instances.</para>
|
||||
|
||||
<para>When you call <methodname>getResource()</methodname> on a specific
|
||||
application context, and the location path specified doesn't have a
|
||||
specific prefix, you will get back a
|
||||
<interfacename>Resource</interfacename> type that is appropriate to that
|
||||
particular application context. For example, assume the following snippet
|
||||
of code was executed against a
|
||||
<classname>ClassPathXmlApplicationContext</classname> instance:</para>
|
||||
|
||||
<programlisting>Resource template = ctx.getResource("some/resource/path/myTemplate.txt);</programlisting>
|
||||
|
||||
<para>What would be returned would be a
|
||||
<classname>ClassPathResource</classname>; if the same method was executed
|
||||
against a <classname>FileSystemXmlApplicationContext</classname> instance,
|
||||
you'd get back a <classname>FileSystemResource</classname>. For a
|
||||
<classname>WebApplicationContext</classname>, you'd get back a
|
||||
<classname>ServletContextResource</classname>, and so on.</para>
|
||||
|
||||
<para>As such, you can load resources in a fashion appropriate to the
|
||||
particular application context.</para>
|
||||
|
||||
<para>On the other hand, you may also force
|
||||
<classname>ClassPathResource</classname> to be used, regardless of the
|
||||
application context type, by specifying the special
|
||||
<literal>classpath:</literal> prefix:</para>
|
||||
|
||||
<programlisting>Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt);</programlisting>
|
||||
|
||||
<para>Similarly, one can force a <classname>UrlResource</classname> to be
|
||||
used by specifying any of the standard <classname>java.net.URL</classname>
|
||||
prefixes:</para>
|
||||
|
||||
<programlisting>Resource template = ctx.getResource("file:/some/resource/path/myTemplate.txt);</programlisting>
|
||||
|
||||
<programlisting>Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt);</programlisting>
|
||||
|
||||
<para>The following table summarizes the strategy for converting
|
||||
<classname>String</classname>s to
|
||||
<interfacename>Resource</interfacename>s:</para>
|
||||
|
||||
<table pgwide="1" id="resources-resource-strings">
|
||||
<title>Resource strings</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<colspec align="left" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Prefix</entry>
|
||||
|
||||
<entry align="center">Example</entry>
|
||||
|
||||
<entry align="center">Explanation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><para>classpath:</para></entry>
|
||||
|
||||
<entry><para> <literal>classpath:com/myapp/config.xml</literal>
|
||||
</para></entry>
|
||||
|
||||
<entry><para>Loaded from the classpath.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para>file:</para></entry>
|
||||
|
||||
<entry><para> <literal>file:/data/config.xml</literal>
|
||||
</para></entry>
|
||||
|
||||
<entry><para> Loaded as a <classname>URL</classname>, from the
|
||||
filesystem. <footnote>
|
||||
<para>But see also the section entitled <xref
|
||||
linkend="resources-filesystemresource-caveats" />.</para>
|
||||
</footnote> </para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para>http:</para></entry>
|
||||
|
||||
<entry><para> <literal>http://myserver/logo.png</literal>
|
||||
</para></entry>
|
||||
|
||||
<entry><para>Loaded as a
|
||||
<classname>URL</classname>.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para>(none)</para></entry>
|
||||
|
||||
<entry><para> <literal>/data/config.xml</literal> </para></entry>
|
||||
|
||||
<entry><para> Depends on the underlying
|
||||
<interfacename>ApplicationContext</interfacename>. </para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="resources-resourceloaderaware">
|
||||
<title>The <interfacename>ResourceLoaderAware</interfacename> interface</title>
|
||||
|
||||
<para>The <interfacename>ResourceLoaderAware</interfacename> interface is
|
||||
a special marker interface, identifying objects that expect to be provided
|
||||
with a <interfacename>ResourceLoader</interfacename> reference.</para>
|
||||
|
||||
<programlisting><![CDATA[public interface ResourceLoaderAware {
|
||||
|
||||
void setResourceLoader(ResourceLoader resourceLoader);
|
||||
}]]></programlisting>
|
||||
|
||||
<para>When a class implements
|
||||
<interfacename>ResourceLoaderAware</interfacename> and is deployed into an
|
||||
application context (as a Spring-managed bean), it is recognized as
|
||||
<interfacename>ResourceLoaderAware</interfacename> by the application
|
||||
context. The application context will then invoke the
|
||||
<methodname>setResourceLoader(ResourceLoader)</methodname>, supplying
|
||||
itself as the argument (remember, all application contexts in Spring
|
||||
implement the <interfacename>ResourceLoader</interfacename>
|
||||
interface).</para>
|
||||
|
||||
<para>Of course, since an
|
||||
<interfacename>ApplicationContext</interfacename> is a
|
||||
<interfacename>ResourceLoader</interfacename>, the bean could also
|
||||
implement the <interfacename>ApplicationContextAware</interfacename>
|
||||
interface and use the supplied application context directly to load
|
||||
resources, but in general, it's better to use the specialized
|
||||
<interfacename>ResourceLoader</interfacename> interface if that's all
|
||||
that's needed. The code would just be coupled to the resource loading
|
||||
interface, which can be considered a utility interface, and not the whole
|
||||
Spring <interfacename>ApplicationContext</interfacename> interface.</para>
|
||||
|
||||
<para>As of Spring 2.5, you can rely upon autowiring of the
|
||||
<interfacename>ResourceLoader</interfacename> as an alternative to
|
||||
implementing the <interfacename>ResourceLoaderAware</interfacename> interface.
|
||||
The "traditional" <literal>constructor</literal> and <literal>byType</literal>
|
||||
autowiring modes (as described in the section entitled
|
||||
<xref linkend="beans-factory-autowire"/>) are now capable of providing a
|
||||
dependency of type <interfacename>ResourceLoader</interfacename> for either a
|
||||
constructor argument or setter method parameter respectively. For more flexibility
|
||||
(including the ability to autowire fields and multiple parameter methods), consider
|
||||
using the new annotation-based autowiring features. In that case, the
|
||||
<interfacename>ResourceLoader</interfacename> will be autowired into a field,
|
||||
constructor argument, or method parameter that is expecting the
|
||||
<interfacename>ResourceLoader</interfacename> type as long as the field,
|
||||
constructor, or method in question carries the
|
||||
<interfacename>@Autowired</interfacename> annotation. For more information,
|
||||
see the section entitled <xref linkend="beans-autowired-annotation"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-as-dependencies">
|
||||
<title><literal>Resources</literal> as dependencies</title>
|
||||
|
||||
<para>If the bean itself is going to determine and supply the resource
|
||||
path through some sort of dynamic process, it probably makes sense for the
|
||||
bean to use the <interfacename>ResourceLoader</interfacename> interface to
|
||||
load resources. Consider as an example the loading of a template of some
|
||||
sort, where the specific resource that is needed depends on the role of
|
||||
the user. If the resources are static, it makes sense to eliminate the use
|
||||
of the <interfacename>ResourceLoader</interfacename> interface completely,
|
||||
and just have the bean expose the <interfacename>Resource</interfacename>
|
||||
properties it needs, and expect that they will be injected into it.</para>
|
||||
|
||||
<para>What makes it trivial to then inject these properties, is that all
|
||||
application contexts register and use a special JavaBeans
|
||||
<interfacename>PropertyEditor</interfacename> which can convert
|
||||
<classname>String</classname> paths to
|
||||
<interfacename>Resource</interfacename> objects. So if
|
||||
<literal>myBean</literal> has a template property of type
|
||||
<interfacename>Resource</interfacename>, it can be configured with a
|
||||
simple string for that resource, as follows:</para>
|
||||
|
||||
<programlisting><![CDATA[<bean id="myBean" class="...">
|
||||
<property name="template" value="some/resource/path/myTemplate.txt"/>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
<para>Note that the resource path has no prefix, so because the
|
||||
application context itself is going to be used as the
|
||||
<interfacename>ResourceLoader</interfacename>, the resource itself will be
|
||||
loaded via a <classname>ClassPathResource</classname>,
|
||||
<literal>FileSystemResource</literal>, or
|
||||
<classname>ServletContextResource</classname> (as appropriate)
|
||||
depending on the exact type of the context.</para>
|
||||
|
||||
<para>If there is a need to force a specific
|
||||
<interfacename>Resource</interfacename> type to be used, then a prefix may
|
||||
be used. The following two examples show how to force a
|
||||
<classname>ClassPathResource</classname> and a
|
||||
<classname>UrlResource</classname> (the latter being used to access a
|
||||
filesystem file).</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="template" value="classpath:some/resource/path/myTemplate.txt">]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<property name="template" value="file:/some/resource/path/myTemplate.txt"/>]]></programlisting>
|
||||
</section>
|
||||
|
||||
<section id="resources-app-ctx">
|
||||
<title>Application contexts and <interfacename>Resource</interfacename> paths</title>
|
||||
|
||||
<section id="resources-app-ctx-construction">
|
||||
<title>Constructing application contexts</title>
|
||||
|
||||
<para>An application context constructor (for a specific application
|
||||
context type) generally takes a string or array of strings as the
|
||||
location path(s) of the resource(s) such as XML files that make up the
|
||||
definition of the context.</para>
|
||||
|
||||
<para>When such a location path doesn't have a prefix, the specific
|
||||
<interfacename>Resource</interfacename> type built from that path and
|
||||
used to load the bean definitions, depends on and is appropriate to the
|
||||
specific application context. For example, if you create a
|
||||
<classname>ClassPathXmlApplicationContext</classname> as follows:</para>
|
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");]]></programlisting>
|
||||
|
||||
<para>The bean definitions will be loaded from the classpath, as a
|
||||
<classname></classname><classname>ClassPathResource</classname> will be
|
||||
used. But if you create a
|
||||
<classname>FileSystemXmlApplicationContext</classname> as
|
||||
follows:</para>
|
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("conf/appContext.xml");]]></programlisting>
|
||||
|
||||
<para>The bean definition will be loaded from a filesystem location, in
|
||||
this case relative to the current working directory.</para>
|
||||
|
||||
<para>Note that the use of the special classpath prefix or a standard
|
||||
URL prefix on the location path will override the default type of
|
||||
<interfacename>Resource</interfacename> created to load the definition.
|
||||
So this <classname>FileSystemXmlApplicationContext</classname>...</para>
|
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");]]></programlisting>
|
||||
|
||||
<para>... will actually load its bean definitions from the classpath.
|
||||
However, it is still a <classname>FileSystemXmlApplicationContext</classname>. If it is
|
||||
subsequently used as a <interfacename>ResourceLoader</interfacename>,
|
||||
any unprefixed paths will still be treated as filesystem paths.</para>
|
||||
|
||||
<section id="resources-app-ctx-classpathxml">
|
||||
<title>Constructing <classname>ClassPathXmlApplicationContext</classname> instances - shortcuts</title>
|
||||
|
||||
<para>The <classname>ClassPathXmlApplicationContext</classname>
|
||||
exposes a number of constructors to enable convenient instantiation.
|
||||
The basic idea is that one supplies merely a string array containing
|
||||
just the filenames of the XML files themselves (without the leading
|
||||
path information), and one <emphasis>also</emphasis> supplies a
|
||||
<classname>Class</classname>; the
|
||||
<classname>ClassPathXmlApplicationContext</classname> will derive the
|
||||
path information from the supplied class.</para>
|
||||
|
||||
<para>An example will hopefully make this clear. Consider a directory
|
||||
layout that looks like this:</para>
|
||||
|
||||
<programlisting><![CDATA[com/
|
||||
foo/
|
||||
services.xml
|
||||
daos.xml
|
||||
MessengerService.class]]></programlisting>
|
||||
|
||||
<para>A <classname>ClassPathXmlApplicationContext</classname> instance
|
||||
composed of the beans defined in the <literal>'services.xml'</literal>
|
||||
and <literal>'daos.xml'</literal> could be instantiated like
|
||||
so...</para>
|
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
new String[] {"services.xml", "daos.xml"}, MessengerService.class);]]></programlisting>
|
||||
|
||||
<para>Please do consult the Javadocs for the
|
||||
<classname>ClassPathXmlApplicationContext</classname> class for
|
||||
details of the various constructors.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-app-ctx-wildcards-in-resource-paths">
|
||||
<title>Wildcards in application context constructor resource paths</title>
|
||||
|
||||
<para>The resource paths in application context constructor values may
|
||||
be a simple path (as shown above) which has a one-to-one mapping to a
|
||||
target Resource, or alternately may contain the special "classpath*:"
|
||||
prefix and/or internal Ant-style regular expressions (matched using
|
||||
Spring's <classname>PathMatcher</classname> utility). Both of the latter
|
||||
are effectively wildcards</para>
|
||||
|
||||
<para>One use for this mechanism is when doing component-style
|
||||
application assembly. All components can 'publish' context definition
|
||||
fragments to a well-known location path, and when the final application
|
||||
context is created using the same path prefixed via
|
||||
<literal>classpath*:</literal>, all component fragments will be picked
|
||||
up automatically.</para>
|
||||
|
||||
<para>Note that this wildcarding is specific to use of resource paths in
|
||||
application context constructors (or when using the
|
||||
<classname>PathMatcher</classname> utility class hierarchy directly),
|
||||
and is resolved at construction time. It has nothing to do with the
|
||||
<interfacename>Resource</interfacename> type itself. It's not possible
|
||||
to use the <literal>classpath*:</literal> prefix to construct an actual
|
||||
<interfacename>Resource</interfacename>, as a resource points to just
|
||||
one resource at a time.</para>
|
||||
|
||||
<section id="resources-app-ctx-ant-patterns-in-paths">
|
||||
<title>Ant-style Patterns</title>
|
||||
|
||||
<para>When the path location contains an Ant-style pattern, for example:</para>
|
||||
|
||||
<programlisting><![CDATA[ /WEB-INF/*-context.xml
|
||||
com/mycompany/**/applicationContext.xml
|
||||
file:C:/some/path/*-context.xml
|
||||
classpath:com/mycompany/**/applicationContext.xml]]></programlisting>
|
||||
|
||||
<para>... the resolver follows a more complex but defined procedure to
|
||||
try to resolve the wildcard. It produces a Resource for the path up to
|
||||
the last non-wildcard segment and obtains a URL from it. If this URL
|
||||
is not a "jar:" URL or container-specific variant (e.g.
|
||||
"<literal>zip:</literal>" in WebLogic, "<literal>wsjar</literal>" in
|
||||
WebSphere, etc.), then a <classname>java.io.File</classname> is
|
||||
obtained from it and used to resolve the wildcard by traversing the
|
||||
filesystem. In the case of a jar URL, the resolver either gets a
|
||||
<classname>java.net.JarURLConnection</classname> from it or manually
|
||||
parses the jar URL and then traverses the contents of the jar file
|
||||
to resolve the wildcards.</para>
|
||||
|
||||
<section id="resources-app-ctx-portability">
|
||||
<title>Implications on portability</title>
|
||||
|
||||
<para>If the specified path is already a file URL (either
|
||||
explicitly, or implicitly because the base
|
||||
<interfacename>ResourceLoader</interfacename> is a
|
||||
filesystem one, then wildcarding is guaranteed to work in a
|
||||
completely portable fashion.</para>
|
||||
|
||||
<para>If the specified path is a classpath location, then the
|
||||
resolver must obtain the last non-wildcard path segment URL via a
|
||||
<methodname>Classloader.getResource()</methodname> call. Since this
|
||||
is just a node of the path (not the file at the end) it is actually
|
||||
undefined (in the <classname>ClassLoader</classname> Javadocs)
|
||||
exactly what sort of a URL is returned in this case. In practice, it
|
||||
is always a <classname>java.io.File</classname> representing the
|
||||
directory, where the classpath resource resolves to a filesystem
|
||||
location, or a jar URL of some sort, where the classpath resource
|
||||
resolves to a jar location. Still, there is a portability concern on
|
||||
this operation.</para>
|
||||
|
||||
<para>If a jar URL is obtained for the last non-wildcard segment,
|
||||
the resolver must be able to get a
|
||||
<classname>java.net.JarURLConnection</classname> from it, or
|
||||
manually parse the jar URL, to be able to walk the contents of the
|
||||
jar, and resolve the wildcard. This will work in most environments,
|
||||
but will fail in others, and it is strongly recommended that the
|
||||
wildcard resolution of resources coming from jars be thoroughly
|
||||
tested in your specific environment before you rely on it.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-classpath-wildcards">
|
||||
<title>The <literal>classpath*:</literal> prefix</title>
|
||||
|
||||
<para>When constructing an XML-based application context, a location
|
||||
string may use the special <literal>classpath*:</literal>
|
||||
prefix:</para>
|
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx =
|
||||
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");]]></programlisting>
|
||||
|
||||
<para>This special prefix specifies that all classpath resources that
|
||||
match the given name must be obtained (internally, this essentially
|
||||
happens via a <methodname>ClassLoader.getResources(...)</methodname>
|
||||
call), and then merged to form the final application context
|
||||
definition.</para>
|
||||
|
||||
<note>
|
||||
<title>Classpath*: portability</title>
|
||||
|
||||
<para>The wildcard classpath relies on the <literal>getResources()</literal> method of the
|
||||
underlying classloader. As most application servers nowadays supply
|
||||
their own classloader implementation, the behavior might differ
|
||||
especially when dealing with jar files. A simple test to check if
|
||||
<literal>classpath*</literal> works is to use the classloader to load a file from
|
||||
within a jar on the classpath:
|
||||
<literal>getClass().getClassLoader().getResources("<someFileInsideTheJar>")</literal>.
|
||||
Try this test with files that have the same name but are placed
|
||||
inside two different locations. In case an inappropriate result is
|
||||
returned, check the application server documentation for settings
|
||||
that might affect the classloader behavior.</para>
|
||||
</note>
|
||||
|
||||
<para>The "<literal>classpath*:</literal>" prefix can also be combined
|
||||
with a <literal>PathMatcher</literal> pattern in the rest of the location path, for
|
||||
example "<literal>classpath*:META-INF/*-beans.xml</literal>". In this
|
||||
case, the resolution strategy is fairly simple: a
|
||||
ClassLoader.getResources() call is used on the last non-wildcard path
|
||||
segment to get all the matching resources in the class loader
|
||||
hierarchy, and then off each resource the same PathMatcher resoltion
|
||||
strategy described above is used for the wildcard subpath.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-wildcards-in-path-other-stuff">
|
||||
<title>Other notes relating to wildcards</title>
|
||||
|
||||
<para>Please note that "<literal>classpath*:</literal>" when
|
||||
combined with Ant-style patterns will only work reliably with at least
|
||||
one root directory before the pattern starts, unless the actual target
|
||||
files reside in the file system. This means that a pattern like
|
||||
"<literal>classpath*:*.xml</literal>" will not retrieve files from the
|
||||
root of jar files but rather only from the root of expanded
|
||||
directories. This originates from a limitation in the JDK's
|
||||
<methodname>ClassLoader.getResources()</methodname> method which only
|
||||
returns file system locations for a passed-in empty string (indicating
|
||||
potential roots to search).</para>
|
||||
|
||||
<para>Ant-style patterns with "<literal>classpath:</literal>"
|
||||
resources are not guaranteed to find matching resources if the root
|
||||
package to search is available in multiple class path locations. This
|
||||
is because a resource such as</para>
|
||||
|
||||
<programlisting><![CDATA[ com/mycompany/package1/service-context.xml]]></programlisting>
|
||||
|
||||
<para>may be in only one location, but when a path such as</para>
|
||||
|
||||
<programlisting><![CDATA[ classpath:com/mycompany/**/service-context.xml]]></programlisting>
|
||||
|
||||
<para>is used to try to resolve it, the resolver will work off the (first) URL
|
||||
returned by <methodname>getResource("com/mycompany")</methodname>;. If
|
||||
this base package node exists in multiple classloader locations, the
|
||||
actual end resource may not be underneath. Therefore, preferably, use
|
||||
"<literal>classpath*:</literal>" with the same Ant-style pattern in
|
||||
such a case, which will search all class path locations that contain
|
||||
the root package.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-filesystemresource-caveats">
|
||||
<title><classname>FileSystemResource</classname> caveats</title>
|
||||
|
||||
<para>A <classname>FileSystemResource</classname> that is not attached
|
||||
to a <classname>FileSystemApplicationContext</classname> (that is, a
|
||||
<classname>FileSystemApplicationContext</classname> is not the actual
|
||||
<interfacename>ResourceLoader</interfacename>) will treat absolute vs.
|
||||
relative paths as you would expect. Relative paths are relative to the
|
||||
current working directory, while absolute paths are relative to the root
|
||||
of the filesystem.</para>
|
||||
|
||||
<para>For backwards compatibility (historical) reasons however, this
|
||||
changes when the <classname>FileSystemApplicationContext</classname> is
|
||||
the <literal>ResourceLoader</literal>. The
|
||||
<classname>FileSystemApplicationContext</classname> simply forces all
|
||||
attached <classname>FileSystemResource</classname> instances to treat
|
||||
all location paths as relative, whether they start with a leading slash
|
||||
or not. In practice, this means the following are equivalent:</para>
|
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("conf/context.xml");]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("/conf/context.xml");]]></programlisting>
|
||||
|
||||
<para>As are the following: (Even though it would make sense for them to
|
||||
be different, as one case is relative and the other absolute.)</para>
|
||||
|
||||
<programlisting><![CDATA[FileSystemXmlApplicationContext ctx = ...;
|
||||
ctx.getResource("some/resource/path/myTemplate.txt");]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[FileSystemXmlApplicationContext ctx = ...;
|
||||
ctx.getResource("/some/resource/path/myTemplate.txt");]]></programlisting>
|
||||
|
||||
<para>In practice, if true absolute filesystem paths are needed, it is
|
||||
better to forgo the use of absolute paths with
|
||||
<classname>FileSystemResource</classname> /
|
||||
<classname>FileSystemXmlApplicationContext</classname>, and just force
|
||||
the use of a <classname>UrlResource</classname>, by using the
|
||||
<literal>file:</literal> URL prefix.</para>
|
||||
|
||||
<programlisting><lineannotation>// actual context type doesn't matter, the <interfacename>Resource</interfacename> will always be <classname>UrlResource</classname></lineannotation><![CDATA[
|
||||
ctx.getResource("file:/some/resource/path/myTemplate.txt");]]></programlisting>
|
||||
|
||||
<programlisting><lineannotation>// force this FileSystemXmlApplicationContext to load its definition via a <classname>UrlResource</classname></lineannotation><![CDATA[
|
||||
ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("file:/conf/context.xml");]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,499 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<chapter id="scheduling">
|
||||
<title>Scheduling and Thread Pooling</title>
|
||||
<section id="scheduling-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
The Spring Framework features integration classes for scheduling support. Currently, Spring
|
||||
supports the <classname>Timer</classname>, part of the JDK since 1.3, and the
|
||||
Quartz Scheduler (<ulink url="http://www.opensymphony.com/quartz/"/>). Both schedulers
|
||||
are set up using a <interfacename>FactoryBean</interfacename> with optional references
|
||||
to <classname>Timer</classname> or <classname>Trigger</classname> instances, respectively.
|
||||
Furthermore, a convenience class for both the Quartz Scheduler and the <classname>Timer</classname> is
|
||||
available that allows you to invoke a method of an existing target object
|
||||
(analogous to the normal <classname>MethodInvokingFactoryBean</classname> operation).
|
||||
Spring also features classes for thread pooling that abstract
|
||||
away differences between Java SE 1.4, Java SE 5 and Java EE environments.
|
||||
</para>
|
||||
</section>
|
||||
<section id="scheduling-quartz">
|
||||
<title>Using the OpenSymphony Quartz Scheduler</title>
|
||||
<para>Quartz uses <classname>Trigger</classname>, <classname>Job</classname> and
|
||||
<classname>JobDetail</classname> objects to realize scheduling of all kinds of jobs.
|
||||
For the basic concepts behind Quartz, have a look at
|
||||
<ulink url="http://www.opensymphony.com/quartz" />. For convenience purposes,
|
||||
Spring offers a couple of classes that simplify the usage of Quartz within
|
||||
Spring-based applications.
|
||||
</para>
|
||||
<section id="scheduling-quartz-jobdetail">
|
||||
<title>Using the JobDetailBean</title>
|
||||
<para>
|
||||
<classname>JobDetail</classname> objects contain all information needed to
|
||||
run a job. The Spring Framework provides a <classname>JobDetailBean</classname>
|
||||
that makes the <classname>JobDetail</classname> more of an actual JavaBean
|
||||
with sensible defaults. Let's have a look at an example:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailBean">
|
||||
<property name="jobClass" value="example.ExampleJob" />
|
||||
<property name="jobDataAsMap">
|
||||
<map>
|
||||
<entry key="timeout" value="5" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>]]></programlisting>
|
||||
<para>The job detail bean has all information it needs to run the job (<classname>ExampleJob</classname>).
|
||||
The timeout is specified in the job data map. The job data map is
|
||||
available through the <classname>JobExecutionContext</classname>
|
||||
(passed to you at execution time), but the <classname>JobDetailBean</classname>
|
||||
also maps the properties from the job data map to properties of the actual job.
|
||||
So in this case, if the <classname>ExampleJob</classname> contains a property
|
||||
named <literal>timeout</literal>, the <classname>JobDetailBean</classname> will
|
||||
automatically apply it:</para>
|
||||
<programlisting><![CDATA[package example;
|
||||
|
||||
public class ExampleJob extends QuartzJobBean {
|
||||
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
* Setter called after the ExampleJob is instantiated
|
||||
* with the value from the JobDetailBean (5)
|
||||
*/
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
|
||||
]]><lineannotation>// do the actual work</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>All additional settings from the job detail bean are of course available to you as well.</para>
|
||||
<para><emphasis>Note: Using the <literal>name</literal> and <literal>group</literal> properties,
|
||||
you can modify the name and the group of the job, respectively. By default, the name of
|
||||
the job matches the bean name of the job detail bean (in the example above, this is
|
||||
<literal>exampleJob</literal>).</emphasis></para>
|
||||
</section>
|
||||
<section id="scheduling-quartz-method-invoking-job">
|
||||
<title>Using the <classname>MethodInvokingJobDetailFactoryBean</classname></title>
|
||||
<para>Often you just need to invoke a method on a specific object. Using the
|
||||
<classname>MethodInvokingJobDetailFactoryBean</classname> you can do exactly this:</para>
|
||||
<programlisting><![CDATA[<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
|
||||
<property name="targetObject" ref="exampleBusinessObject" />
|
||||
<property name="targetMethod" value="doIt" />
|
||||
</bean>]]></programlisting>
|
||||
<para>The above example will result in the <literal>doIt</literal> method being called on the
|
||||
<literal>exampleBusinessObject</literal> method (see below):</para>
|
||||
<programlisting><![CDATA[public class ExampleBusinessObject {
|
||||
|
||||
]]><lineannotation>// properties and collaborators</lineannotation><![CDATA[
|
||||
|
||||
public void doIt() {
|
||||
]]><lineannotation>// do the actual work</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<bean id="exampleBusinessObject" class="examples.ExampleBusinessObject"/>]]></programlisting>
|
||||
<para>Using the <classname>MethodInvokingJobDetailFactoryBean</classname>, you don't need to
|
||||
create one-line jobs that just invoke a method, and you only need to create the actual
|
||||
business object and wire up the detail object.</para>
|
||||
<para>By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering
|
||||
with each other. If you specify two triggers for the same <classname>JobDetail</classname>,
|
||||
it might be possible that before the first job has finished, the second one will start.
|
||||
If <classname>JobDetail</classname> classes implement the
|
||||
<interfacename>Stateful</interfacename> interface, this won't happen. The second job
|
||||
will not start before the first one has finished. To make jobs resulting from the
|
||||
<classname>MethodInvokingJobDetailFactoryBean</classname> non-concurrent, set the
|
||||
<literal>concurrent</literal> flag to <literal>false</literal>.</para>
|
||||
<programlisting><![CDATA[
|
||||
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
|
||||
<property name="targetObject" ref="exampleBusinessObject" />
|
||||
<property name="targetMethod" value="doIt" />
|
||||
<property name="concurrent" value="false" />
|
||||
</bean>]]></programlisting>
|
||||
<note>
|
||||
<para>By default, jobs will run in a concurrent fashion.</para>
|
||||
</note>
|
||||
</section>
|
||||
<section id="scheduling-quartz-cron">
|
||||
<title>Wiring up jobs using triggers and the <classname>SchedulerFactoryBean</classname></title>
|
||||
<para>
|
||||
We've created job details and jobs. We've also reviewed the convenience bean
|
||||
that allows to you invoke a method on a specific object. Of course, we still need
|
||||
to schedule the jobs themselves. This is done using triggers and a
|
||||
<classname>SchedulerFactoryBean</classname>. Several triggers are available
|
||||
within Quartz. Spring offers two subclassed triggers with convenient defaults:
|
||||
<classname>CronTriggerBean</classname> and <classname>SimpleTriggerBean</classname>.
|
||||
</para>
|
||||
<para>
|
||||
Triggers need to be scheduled. Spring offers a <classname>SchedulerFactoryBean</classname>
|
||||
that exposes triggers to be set as properties. <classname>SchedulerFactoryBean</classname>
|
||||
schedules the actual jobs with those triggers.
|
||||
</para>
|
||||
<para>Find below a couple of examples:</para>
|
||||
<programlisting><![CDATA[<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
|
||||
<!-- see the example of method invoking job above -->
|
||||
<property name="jobDetail" ref="jobDetail" />
|
||||
<!-- 10 seconds -->
|
||||
<property name="startDelay" value="10000" />
|
||||
<!-- repeat every 50 seconds -->
|
||||
<property name="repeatInterval" value="50000" />
|
||||
</bean>
|
||||
|
||||
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
|
||||
<property name="jobDetail" ref="exampleJob" />
|
||||
<!-- run every morning at 6 AM -->
|
||||
<property name="cronExpression" value="0 0 6 * * ?" />
|
||||
</bean>]]></programlisting>
|
||||
<para>Now we've set up two triggers, one running every 50 seconds with a starting delay of
|
||||
10 seconds and one every morning at 6 AM. To finalize everything, we need to set up the
|
||||
<classname>SchedulerFactoryBean</classname>:</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
|
||||
<property name="triggers">
|
||||
<list>
|
||||
<ref bean="cronTrigger" />
|
||||
<ref bean="simpleTrigger" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
More properties are available for the <classname>SchedulerFactoryBean</classname> for you
|
||||
to set, such as the calendars used by the job details, properties to customize Quartz with,
|
||||
etc. Have a look at the
|
||||
<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/scheduling/quartz/SchedulerFactoryBean.html">SchedulerFactoryBean Javadoc</ulink>
|
||||
for more information.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="scheduling-jdk-timer">
|
||||
<title>Using JDK Timer support</title>
|
||||
<para>
|
||||
The other way to schedule jobs in Spring is to use JDK
|
||||
<classname>Timer</classname> objects. You can create custom timers or
|
||||
use the timer that invokes methods. Wiring timers is done using the
|
||||
<classname>TimerFactoryBean</classname>.
|
||||
</para>
|
||||
<section id="scheduling-jdk-timer-creating">
|
||||
<title>Creating custom timers</title>
|
||||
<para>
|
||||
Using the <classname>TimerTask</classname> you can create customer
|
||||
timer tasks, similar to Quartz jobs:
|
||||
</para>
|
||||
<programlisting><![CDATA[public class CheckEmailAddresses extends TimerTask {
|
||||
|
||||
private List emailAddresses;
|
||||
|
||||
public void setEmailAddresses(List emailAddresses) {
|
||||
this.emailAddresses = emailAddresses;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
]]><lineannotation>// iterate over all email addresses and archive them</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
Wiring it up is simple:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean id="checkEmail" class="examples.CheckEmailAddress">
|
||||
<property name="emailAddresses">
|
||||
<list>
|
||||
<value>test@springframework.org</value>
|
||||
<value>foo@bar.com</value>
|
||||
<value>john@doe.net</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
|
||||
]]><lineannotation><!-- wait 10 seconds before starting repeated execution --></lineannotation><![CDATA[
|
||||
<property name="delay" value="10000" />
|
||||
]]><lineannotation><!-- run every 50 seconds --></lineannotation><![CDATA[
|
||||
<property name="period" value="50000" />
|
||||
<property name="timerTask" ref="checkEmail" />
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
<emphasis>
|
||||
Note that letting the task only run once can be done by changing the
|
||||
<literal>period</literal> property to 0 (or a negative value).
|
||||
</emphasis>
|
||||
</para>
|
||||
</section>
|
||||
<section id="scheduling-jdk-timer-method-invoking-task">
|
||||
<title>Using the <classname>MethodInvokingTimerTaskFactoryBean</classname></title>
|
||||
<para>
|
||||
Similar to the Quartz support, the <classname>Timer</classname> support also features
|
||||
a component that allows you to periodically invoke a method:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean id="doIt" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
|
||||
<property name="targetObject" ref="exampleBusinessObject" />
|
||||
<property name="targetMethod" value="doIt" />
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
The above example will result in the <literal>doIt</literal> method being called on the
|
||||
<literal>exampleBusinessObject</literal> (see below):
|
||||
</para>
|
||||
<programlisting><![CDATA[public class BusinessObject {
|
||||
|
||||
]]><lineannotation>// properties and collaborators</lineannotation><![CDATA[
|
||||
|
||||
public void doIt() {
|
||||
]]><lineannotation>// do the actual work</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Changing the <literal>timerTask</literal> reference of the
|
||||
<classname>ScheduledTimerTask</classname> example to the bean <literal>doIt</literal>
|
||||
will result in the <literal>doIt</literal> method being executed on a fixed schedule.</para>
|
||||
</section>
|
||||
<section id="scheduling-jdk-timer-factory-bean">
|
||||
<title>Wrapping up: setting up the tasks using the <classname>TimerFactoryBean</classname></title>
|
||||
<para>The <classname>TimerFactoryBean</classname> is similar to the Quartz
|
||||
<classname>SchedulerFactoryBean</classname> in that it serves the same
|
||||
purpose: setting up the actual scheduling. The <classname>TimerFactoryBean</classname>
|
||||
sets up an actual <classname>Timer</classname> and schedules the tasks it has
|
||||
references to. You can specify whether or not daemon threads should be used.</para>
|
||||
<programlisting><![CDATA[<bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
|
||||
<property name="scheduledTimerTasks">
|
||||
<list>
|
||||
]]><lineannotation><!-- see the example above --></lineannotation><![CDATA[
|
||||
<ref bean="scheduledTask" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
<section id="scheduling-task-executor">
|
||||
<title>The Spring <interfacename>TaskExecutor</interfacename> abstraction</title>
|
||||
<para>Spring 2.0 introduces a new abstraction for dealing with
|
||||
executors. Executors are the Java 5 name for the concept of
|
||||
thread pools. The "executor" naming is due to the fact that there
|
||||
is no guarantee that the underlying implementation is actually a
|
||||
pool; an executor may be single-threaded or even synchronous.
|
||||
Spring's abstraction hides implementation details between
|
||||
Java SE 1.4, Java SE 5 and Java EE environments.</para>
|
||||
<title>The <interfacename>TaskExecutor</interfacename> interface</title>
|
||||
<para>Spring's <interfacename>TaskExecutor</interfacename> interface is
|
||||
identical to the <classname>java.util.concurrent.Executor</classname>
|
||||
interface. In fact, its primary reason for existence is to abstract away
|
||||
the need for Java 5 when using thread pools. The interface has a single
|
||||
method <classname>execute(Runnable task)</classname> that accepts a task
|
||||
for execution based on the semantics and configuration of the thread pool.</para>
|
||||
<para>The <interfacename>TaskExecutor</interfacename> was originally
|
||||
created to give other Spring components an abstraction for thread pooling where
|
||||
needed. Components such as the <classname>ApplicationEventMulticaster</classname>,
|
||||
JMS's <classname>AbstractMessageListenerContainer</classname>,
|
||||
and Quartz integration all use the <interfacename>TaskExecutor</interfacename>
|
||||
abstraction to pool threads. However, if your beans need thread pooling behavior,
|
||||
it is possible to use this abstraction for your own needs.</para>
|
||||
|
||||
<section id="scheduling-task-executor-types">
|
||||
<title><interfacename>TaskExecutor</interfacename> types</title>
|
||||
<para>There are a number of pre-built implementations of
|
||||
<interfacename>TaskExecutor</interfacename> included with the
|
||||
Spring distribution. In all likelihood, you shouldn't ever
|
||||
need to implement your own.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>SimpleAsyncTaskExecutor</classname>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This implementation does not reuse any threads,
|
||||
rather it starts up a new thread for each
|
||||
invocation. However, it does support a
|
||||
concurrency limit which will block any
|
||||
invocations that are over the limit until a slot
|
||||
has been freed up. If you're looking for true
|
||||
pooling, keep scrolling further down the page.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem id="syncTaskExecutor">
|
||||
<para>
|
||||
<classname>SyncTaskExecutor</classname>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This implementation doesn't execute
|
||||
invocations asynchronously. Instead, each
|
||||
invocation takes place in the calling thread. It
|
||||
is primarily used in situations where
|
||||
mutlithreading isn't necessary such as simple
|
||||
test cases.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem id="concurrentTaskExecutor">
|
||||
<para>
|
||||
<classname>ConcurrentTaskExecutor</classname>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This implementation is a wrapper for a Java 5
|
||||
<classname>java.util.concurrent.Executor</classname>.
|
||||
There is an alternative,
|
||||
<classname>ThreadPoolTaskExecutor</classname>,
|
||||
that exposes the <classname>Executor</classname>
|
||||
configuration parameters as bean properties. It
|
||||
is rare to need to use the <classname>ConcurrentTaskExecutor</classname>
|
||||
but if the
|
||||
<link linkend="threadPoolTaskExecutor"><classname>ThreadPoolTaskExecutor</classname></link>
|
||||
isn't robust enough for your needs, the
|
||||
<classname>ConcurrentTaskExecutor</classname>
|
||||
is an alternative.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem id="simpleThreadPoolTaskExecutor">
|
||||
<para>
|
||||
<classname>SimpleThreadPoolTaskExecutor</classname>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This implementation is actually a subclass of
|
||||
Quartz's <classname>SimpleThreadPool</classname>
|
||||
which listens to Spring's lifecycle callbacks.
|
||||
This is typically used when you have a
|
||||
threadpool that may need to be shared by both
|
||||
Quartz and non-Quartz components.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem id="threadPoolTaskExecutor">
|
||||
<para>
|
||||
<classname>ThreadPoolTaskExecutor</classname>
|
||||
</para>
|
||||
|
||||
<sidebar>
|
||||
<para>
|
||||
It is not possible to use any backport or
|
||||
alternate versions of the
|
||||
<classname>java.util.concurrent</classname>
|
||||
package with this implementation. Both Doug
|
||||
Lea's and Dawid Kurzyniec's implementations
|
||||
use different package structures which will
|
||||
prevent them from working correctly.
|
||||
</para>
|
||||
</sidebar>
|
||||
|
||||
<para>
|
||||
This implementation can only be used in a Java 5
|
||||
environment but is also the most commonly used
|
||||
one in that environment. It exposes bean properties for
|
||||
configuring a
|
||||
<classname>java.util.concurrent.ThreadPoolExecutor</classname>
|
||||
and wraps it in a <interfacename>TaskExecutor</interfacename>.
|
||||
If you need something advanced such as a
|
||||
<classname>ScheduledThreadPoolExecutor</classname>,
|
||||
it is recommended that you use a
|
||||
<link linkend="concurrentTaskExecutor"><classname>ConcurrentTaskExecutor</classname></link>
|
||||
instead.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>TimerTaskExecutor</classname>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This implementation uses a single
|
||||
<classname>TimerTask</classname>
|
||||
as its backing implementation. It's different
|
||||
from the
|
||||
<link linkend="syncTaskExecutor"><classname>SyncTaskExecutor</classname></link>
|
||||
in that the method invocations are executed in a
|
||||
separate thread, although they are synchronous
|
||||
in that thread.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>WorkManagerTaskExecutor</classname>
|
||||
</para>
|
||||
|
||||
<sidebar><para>
|
||||
CommonJ is a set of specifications jointly
|
||||
developed between BEA and IBM. These
|
||||
specifications are not Java EE standards, but
|
||||
are standard across BEA's and IBM's
|
||||
Application Server implementations.
|
||||
</para></sidebar>
|
||||
|
||||
<para>
|
||||
This implementation uses the CommonJ WorkManager
|
||||
as its backing implementation and is the central
|
||||
convenience class for setting up a CommonJ
|
||||
WorkManager reference in a Spring context.
|
||||
Similar to the
|
||||
<link linkend="simpleThreadPoolTaskExecutor"><classname>SimpleThreadPoolTaskExecutor</classname></link>,
|
||||
this class implements the WorkManager
|
||||
interface and therefore can be used directly as
|
||||
a WorkManager as well.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section id="scheduling-task-executor-usage">
|
||||
<title>Using a <interfacename>TaskExecutor</interfacename></title>
|
||||
<para>Spring's <interfacename>TaskExecutor</interfacename> implementations
|
||||
are used as simple JavaBeans. In the example below, we define
|
||||
a bean that uses the <classname>ThreadPoolTaskExecutor</classname>
|
||||
to asynchronously print out a set of messages.</para>
|
||||
|
||||
<programlisting><![CDATA[import org.springframework.core.task.TaskExecutor;
|
||||
|
||||
public class TaskExecutorExample {
|
||||
|
||||
private class MessagePrinterTask implements Runnable {
|
||||
|
||||
private String message;
|
||||
|
||||
public MessagePrinterTask(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private TaskExecutor taskExecutor;
|
||||
|
||||
public TaskExecutorExample(TaskExecutor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
public void printMessages() {
|
||||
for(int i = 0; i < 25; i++) {
|
||||
taskExecutor.execute(new MessagePrinterTask("Message" + i));
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>As you can see, rather than retrieving a thread from the
|
||||
pool and executing yourself, you add your <classname>Runnable</classname>
|
||||
to the queue and the <interfacename>TaskExecutor</interfacename>
|
||||
uses its internal rules to decide when the task gets executed.</para>
|
||||
|
||||
<para>To configure the rules that the <interfacename>TaskExecutor</interfacename>
|
||||
will use, simple bean properties have been exposed.</para>
|
||||
|
||||
<programlisting><![CDATA[<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
|
||||
<property name="corePoolSize" value="5" />
|
||||
<property name="maxPoolSize" value="10" />
|
||||
<property name="queueCapacity" value="25" />
|
||||
</bean>
|
||||
|
||||
<bean id="taskExecutorExample" class="TaskExecutorExample">
|
||||
<constructor-arg ref="taskExecutor" />
|
||||
</bean>]]></programlisting>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,346 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
|
||||
<!ENTITY preface SYSTEM "preface.xml">
|
||||
<!ENTITY overview SYSTEM "overview.xml">
|
||||
<!ENTITY whats-new-in-3 SYSTEM "new-in-3.xml">
|
||||
<!ENTITY beans SYSTEM "beans.xml">
|
||||
<!ENTITY resources SYSTEM "resources.xml">
|
||||
<!ENTITY validation SYSTEM "validation.xml">
|
||||
<!ENTITY aop SYSTEM "aop.xml">
|
||||
<!ENTITY aop-api SYSTEM "aop-api.xml">
|
||||
<!ENTITY transaction SYSTEM "transaction.xml">
|
||||
<!ENTITY metadata SYSTEM "metadata.xml">
|
||||
<!ENTITY dao SYSTEM "dao.xml">
|
||||
<!ENTITY jdbc SYSTEM "jdbc.xml">
|
||||
<!ENTITY orm SYSTEM "orm.xml">
|
||||
<!ENTITY mvc SYSTEM "mvc.xml">
|
||||
<!ENTITY view SYSTEM "view.xml">
|
||||
<!ENTITY web-integration SYSTEM "web-integration.xml">
|
||||
<!ENTITY portlet SYSTEM "portlet.xml">
|
||||
<!ENTITY remoting SYSTEM "remoting.xml">
|
||||
<!ENTITY ejb SYSTEM "ejb.xml">
|
||||
<!ENTITY jms SYSTEM "jms.xml">
|
||||
<!ENTITY jmx SYSTEM "jmx.xml">
|
||||
<!ENTITY cci SYSTEM "cci.xml">
|
||||
<!ENTITY mail SYSTEM "mail.xml">
|
||||
<!ENTITY scheduling SYSTEM "scheduling.xml">
|
||||
<!ENTITY testing SYSTEM "testing.xml">
|
||||
<!ENTITY dynamic-languages SYSTEM "dynamic-languages.xml">
|
||||
<!ENTITY xsd-configuration SYSTEM "xsd-configuration.xml">
|
||||
<!ENTITY xml-custom SYSTEM "xml-custom.xml">
|
||||
<!ENTITY dtd SYSTEM "dtd.xml">
|
||||
<!ENTITY spring-tld SYSTEM "spring.tld.xml">
|
||||
<!ENTITY spring-form-tld SYSTEM "spring-form.tld.xml">
|
||||
<!ENTITY swf-sidebar SYSTEM "swf-sidebar.xml">
|
||||
]>
|
||||
<book>
|
||||
<bookinfo>
|
||||
<title>Reference Documentation</title>
|
||||
<subtitle>(Work in progress)</subtitle>
|
||||
<productname>Spring Framework</productname>
|
||||
<releaseinfo>3.0.M3</releaseinfo>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/logo-pdf.png"
|
||||
format="PNG" width="240"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Rod</firstname>
|
||||
<surname>Johnson</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Juergen</firstname>
|
||||
<surname>Hoeller</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Alef</firstname>
|
||||
<surname>Arendsen</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Colin</firstname>
|
||||
<surname>Sampaleanu</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Rob</firstname>
|
||||
<surname>Harrop</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Thomas</firstname>
|
||||
<surname>Risberg</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Darren</firstname>
|
||||
<surname>Davison</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Dmitriy</firstname>
|
||||
<surname>Kopylenko</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Mark</firstname>
|
||||
<surname>Pollack</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Thierry</firstname>
|
||||
<surname>Templier</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Erwin</firstname>
|
||||
<surname>Vervaet</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Portia</firstname>
|
||||
<surname>Tung</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Ben</firstname>
|
||||
<surname>Hale</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Adrian</firstname>
|
||||
<surname>Colyer</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>John</firstname>
|
||||
<surname>Lewis</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Costin</firstname>
|
||||
<surname>Leau</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Mark</firstname>
|
||||
<surname>Fisher</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Sam</firstname>
|
||||
<surname>Brannen</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Ramnivas</firstname>
|
||||
<surname>Laddad</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Arjen</firstname>
|
||||
<surname>Poutsma</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<copyright>
|
||||
<year>2004-2009</year>
|
||||
<holder>Rod Johnson, Juergen Hoeller, Alef Arendsen, Colin Sampaleanu, Rob Harrop, Thomas Risberg, Darren Davison,
|
||||
Dmitriy Kopylenko, Mark Pollack, Thierry Templier, Erwin Vervaet, Portia Tung, Ben Hale, Adrian Colyer, John Lewis, Costin Leau,
|
||||
Mark Fisher, Sam Brannen, Ramnivas Laddad, Arjen Poutsma
|
||||
</holder>
|
||||
</copyright>
|
||||
<legalnotice>
|
||||
<para>Copies of this document may be made for your own use and for
|
||||
distribution to others, provided that you do not charge any
|
||||
fee for such copies and further provided that each copy
|
||||
contains this Copyright Notice, whether distributed in print
|
||||
or electronically.</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
<!-- front matter -->
|
||||
<toc/>
|
||||
&preface;
|
||||
&overview;
|
||||
&whats-new-in-3;
|
||||
<part id="spring-core">
|
||||
<title>Core Technologies</title>
|
||||
<partintro id="spring-core-intro">
|
||||
<para>
|
||||
This initial part of the reference documentation covers
|
||||
all of those technologies that are absolutely integral
|
||||
to the Spring Framework.
|
||||
</para>
|
||||
<para>
|
||||
Foremost amongst these is the Spring Framework's
|
||||
Inversion of Control (IoC) container. A thorough treatment
|
||||
of the Spring Framework's IoC container is closely followed
|
||||
by comprehensive coverage of Spring's Aspect-Oriented
|
||||
Programming (AOP) technologies. The Spring Framework has
|
||||
its own AOP framework, which is conceptually easy to understand,
|
||||
and which successfully addresses the 80% sweet spot of AOP
|
||||
requirements in Java enterprise programming.
|
||||
</para>
|
||||
<para>
|
||||
Coverage of Spring's integration with AspectJ (currently
|
||||
the richest - in terms of features - and certainly most
|
||||
mature AOP implementation in the Java enterprise space)
|
||||
is also provided.
|
||||
</para>
|
||||
<para>
|
||||
Finally, the adoption of the test-driven-development (TDD)
|
||||
approach to software development is certainly advocated by
|
||||
the Spring team, and so coverage of Spring's support for
|
||||
integration testing is covered (alongside best practices for
|
||||
unit testing). The Spring team have found that the correct
|
||||
use of IoC certainly does make both unit and integration
|
||||
testing easier (in that the presence of setter methods and
|
||||
appropriate constructors on classes makes them
|
||||
easier to wire together on a test without having to set up
|
||||
service locator registries and suchlike)... the chapter
|
||||
dedicated solely to testing will hopefully convince you of
|
||||
this as well.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="beans"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="resources"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="validation"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="aop"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="aop-api"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="testing"/></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
&beans;
|
||||
&resources;
|
||||
&validation;
|
||||
&aop;
|
||||
&aop-api;
|
||||
&testing;
|
||||
</part>
|
||||
<part id="spring-middle-tier">
|
||||
<title>Middle Tier Data Access</title>
|
||||
<partintro id="spring-middle-tier-intro">
|
||||
<para>
|
||||
This part of the reference documentation is concerned
|
||||
with the middle tier, and specifically the data access
|
||||
responsibilities of said tier.
|
||||
</para>
|
||||
<para>
|
||||
Spring's comprehensive transaction management support is
|
||||
covered in some detail, followed by thorough coverage of
|
||||
the various middle tier data access frameworks and
|
||||
technologies that the Spring Framework integrates with.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="transaction"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="dao"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="jdbc"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="orm"/></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
&transaction;
|
||||
&dao;
|
||||
&jdbc;
|
||||
&orm;
|
||||
</part>
|
||||
<part id="spring-web">
|
||||
<title>The Web</title>
|
||||
<partintro id="spring-web-intro">
|
||||
<para>
|
||||
This part of the reference documentation covers the
|
||||
Spring Framework's support for the presentation tier
|
||||
(and specifically web-based presentation tiers).
|
||||
</para>
|
||||
<para>
|
||||
The Spring Framework's own web framework,
|
||||
<link linkend="mvc">Spring Web MVC</link>, is covered in
|
||||
the first couple of chapters. A number of the remaining
|
||||
chapters in this part of the reference documentation are
|
||||
concerned with the Spring Framework's integration with
|
||||
other web technologies, such as <link linkend="struts">Struts</link>
|
||||
and <link linkend="jsf">JSF</link> (to name but two).
|
||||
</para>
|
||||
<para>
|
||||
This section concludes with coverage of Spring's MVC
|
||||
<link linkend="portlet">portlet framework</link>.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="mvc"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="view"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="web-integration"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="portlet"/></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
&mvc;
|
||||
&view;
|
||||
&web-integration;
|
||||
&portlet;
|
||||
</part>
|
||||
<part id="spring-integration">
|
||||
<title>Integration</title>
|
||||
<partintro id="spring-integration-intro">
|
||||
<para>
|
||||
This part of the reference documentation covers
|
||||
the Spring Framework's integration with a number of J2EE
|
||||
(and related) technologies.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="remoting"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="ejb"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="jms"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="jmx"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="cci"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="mail"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="scheduling"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="dynamic-language"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="metadata"/></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
&remoting;
|
||||
&ejb;
|
||||
&jms;
|
||||
&jmx;
|
||||
&cci;
|
||||
&mail;
|
||||
&scheduling;
|
||||
&dynamic-languages;
|
||||
&metadata;
|
||||
</part>
|
||||
<!-- back matter -->
|
||||
&xsd-configuration;
|
||||
&xml-custom;
|
||||
&dtd;
|
||||
&spring-tld;
|
||||
&spring-form-tld;
|
||||
</book>
|
||||
|
|
@ -0,0 +1,737 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix id="spring.tld">
|
||||
<title>spring.tld</title>
|
||||
<section id="spring.tld-intro">
|
||||
<title>Introduction</title>
|
||||
</section>
|
||||
<para>One of the view technologies you can use with the Spring Framework
|
||||
is Java Server Pages (JSPs). To help you implement views using Java Server Pages
|
||||
the Spring Framework provides you with some tags for evaluating errors, setting
|
||||
themes and outputting internationalized messages.</para>
|
||||
<para>Please note that the various tags generated by this form tag library
|
||||
are compliant with the <ulink url="http://www.w3.org/TR/xhtml1/">XHTML-1.0-Strict specification</ulink> and attendant <ulink url="http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_XHTML-1.0-Strict">DTD</ulink>.</para>
|
||||
<para>This appendix describes the <literal>spring.tld</literal> tag library.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.bind"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.escapeBody"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.hasBindErrors"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.htmlEscape"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.message"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.nestedPath"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.theme"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.transform"/>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<section id="spring.tld.bind">
|
||||
<title>The <literal>bind</literal> tag</title>
|
||||
<para>
|
||||
Provides BindStatus object for the given bind path.
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
|
||||
</para>
|
||||
<table id="spring.tld.bind.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value. Overrides
|
||||
the default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>ignoreNestedPath</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set whether to ignore a nested path, if any. Default is to not ignore.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>path</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The path to the bean or bean property to bind status
|
||||
information for. For instance account.name, company.address.zipCode
|
||||
or just employee. The status object will exported to the page scope,
|
||||
specifically for this bean or bean property</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section id="spring.tld.escapeBody">
|
||||
<title>The <literal>escapeBody</literal> tag</title>
|
||||
<para>
|
||||
Escapes its enclosed body content, applying HTML escaping and/or JavaScript escaping.
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
|
||||
</para>
|
||||
<table id="spring.tld.escapeBody.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value. Overrides the
|
||||
default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>javaScriptEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set JavaScript escaping for this tag, as boolean value.
|
||||
Default is false.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section id="spring.tld.hasBindErrors">
|
||||
<title>The <literal>hasBindErrors</literal> tag</title>
|
||||
<para>
|
||||
Provides Errors instance in case of bind errors.
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
|
||||
</para>
|
||||
<table id="spring.tld.hasBindErrors.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value.
|
||||
Overrides the default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>name</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The name of the bean in the request, that needs to be
|
||||
inspected for errors. If errors are available for this bean, they
|
||||
will be bound under the 'errors' key.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section id="spring.tld.htmlEscape">
|
||||
<title>The <literal>htmlEscape</literal> tag</title>
|
||||
<para>
|
||||
Sets default HTML escape value for the current page.
|
||||
Overrides a "defaultHtmlEscape" context-param in web.xml, if any.
|
||||
</para>
|
||||
<table id="spring.tld.htmlEscape.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>defaultHtmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set the default value for HTML escaping, to be put
|
||||
into the current PageContext.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section id="spring.tld.message">
|
||||
<title>The <literal>message</literal> tag</title>
|
||||
<para>
|
||||
Retrieves the message with the given code, or text if code isn't resolvable.
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
|
||||
</para>
|
||||
<table id="spring.tld.message.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>arguments</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set optional message arguments for this tag, as a
|
||||
(comma-)delimited String (each String argument can contain JSP EL),
|
||||
an Object array (used as argument array), or a single Object (used
|
||||
as single argument).</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>argumentSeparator</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The separator character to be used for splitting the
|
||||
arguments string value; defaults to a 'comma' (',').</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>code</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The code (key) to use when looking up the message.
|
||||
If code is not provided, the text attribute will be used.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value.
|
||||
Overrides the default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>javaScriptEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set JavaScript escaping for this tag, as boolean value. Default is false.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>message</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>A MessageSourceResolvable argument (direct or through JSP EL).
|
||||
Fits nicely when used in conjunction with Spring's own validation error
|
||||
classes which all implement the MessageSourceResolvable interface. For
|
||||
example, this allows you to iterate over all of the errors in a form,
|
||||
passing each error (using a runtime expression) as the value of this
|
||||
'message' attribute, thus effecting the easy display of such error
|
||||
messages.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>scope</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The scope to use when exporting the result to a variable.
|
||||
This attribute is only used when var is also set. Possible values are
|
||||
page, request, session and application.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>text</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Default text to output when a message for the given code
|
||||
could not be found. If both text and code are not set, the tag will
|
||||
output null.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>var</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The string to use when binding the result to the page,
|
||||
request, session or application scope. If not specified, the result
|
||||
gets outputted to the writer (i.e. typically directly to the JSP).</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section id="spring.tld.nestedPath">
|
||||
<title>The <literal>nestedPath</literal> tag</title>
|
||||
<para>
|
||||
Sets a nested path to be used by the bind tag's path.
|
||||
</para>
|
||||
<table id="spring.tld.nestedPath.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>path</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set the path that this tag should apply. E.g. 'customer'
|
||||
to allow bind paths like 'address.street' rather than
|
||||
'customer.address.street'.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section id="spring.tld.theme">
|
||||
<title>The <literal>theme</literal> tag</title>
|
||||
<para>
|
||||
Retrieves the theme message with the given code, or text if code isn't resolvable.
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
|
||||
</para>
|
||||
<table id="spring.tld.theme.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>arguments</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set optional message arguments for this tag, as a
|
||||
(comma-)delimited String (each String argument can contain JSP EL),
|
||||
an Object array (used as argument array), or a single Object (used
|
||||
as single argument).</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>argumentSeparator</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The separator character to be used for splitting the
|
||||
arguments string value; defaults to a 'comma' (',').</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>code</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The code (key) to use when looking up the message.
|
||||
If code is not provided, the text attribute will be used.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value.
|
||||
Overrides the default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>javaScriptEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set JavaScript escaping for this tag, as boolean value. Default is false.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>message</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>A MessageSourceResolvable argument (direct or through JSP EL).</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>scope</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The scope to use when exporting the result to a variable.
|
||||
This attribute is only used when var is also set. Possible values are
|
||||
page, request, session and application.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>text</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Default text to output when a message for the given code
|
||||
could not be found. If both text and code are not set, the tag will
|
||||
output null.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>var</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The string to use when binding the result to the page,
|
||||
request, session or application scope. If not specified, the result
|
||||
gets outputted to the writer (i.e. typically directly to the JSP).</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section id="spring.tld.transform">
|
||||
<title>The <literal>transform</literal> tag</title>
|
||||
<para>
|
||||
Provides transformation of variables to Strings, using an appropriate
|
||||
custom PropertyEditor from BindTag (can only be used inside BindTag).
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a 'defaultHtmlEscape' context-param in web.xml).
|
||||
</para>
|
||||
<table id="spring.tld.transform.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value. Overrides
|
||||
the default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>scope</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The scope to use when exported the result to a variable.
|
||||
This attribute is only used when var is also set. Possible values are
|
||||
page, request, session and application.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>value</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The value to transform. This is the actual object you want
|
||||
to have transformed (for instance a Date). Using the PropertyEditor that
|
||||
is currently in use by the 'spring:bind' tag.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>var</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The string to use when binding the result to the page,
|
||||
request, session or application scope. If not specified, the result gets
|
||||
outputted to the writer (i.e. typically directly to the JSP).</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
</appendix>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sidebar>
|
||||
<title>Spring Web Flow</title>
|
||||
|
||||
<para>Spring Web Flow (SWF) aims to be the best solution for the management
|
||||
of web application page flow.</para>
|
||||
|
||||
<para>SWF integrates with existing frameworks like Spring MVC, Struts, and
|
||||
JSF, in both servlet and portlet environments. If you have a business
|
||||
process (or processes) that would benefit from a conversational model as
|
||||
opposed to a purely request model, then SWF may be the solution.</para>
|
||||
|
||||
<para>SWF allows you to capture logical page flows as self-contained modules
|
||||
that are reusable in different situations, and as such is ideal for building
|
||||
web application modules that guide the user through controlled navigations
|
||||
that drive business processes.</para>
|
||||
|
||||
<para>For more information about SWF, consult the
|
||||
<ulink url="http://www.springframework.org/webflow">Spring Web Flow website</ulink>.
|
||||
</para>
|
||||
</sidebar>
|
||||
|
|
@ -0,0 +1,749 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="validation">
|
||||
<title>Validation, Data-binding, the <interfacename>BeanWrapper</interfacename>, and <literal>PropertyEditors</literal></title>
|
||||
|
||||
<section id="validation-introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>There are pros and cons for considering validation as business logic,
|
||||
and Spring offers a design for validation (and data binding) that
|
||||
does not exclude either one of them. Specifically validation should not be
|
||||
tied to the web tier, should be easy to localize and it should be
|
||||
possible to plug in any validator available. Considering the above, Spring
|
||||
has come up with a <interfacename>Validator</interfacename> interface that
|
||||
is both basic and eminently usable in every layer of an application.</para>
|
||||
|
||||
<para>Data binding is useful for allowing user input to be dynamically
|
||||
bound to the domain model of an application (or whatever objects you use
|
||||
to process user input). Spring provides the so-called
|
||||
<interfacename>DataBinder</interfacename> to do exactly that. The
|
||||
<interfacename>Validator</interfacename> and the
|
||||
<interfacename>DataBinder</interfacename> make up the <literal>validation</literal> package,
|
||||
which is primarily used in but not limited to the MVC framework.</para>
|
||||
|
||||
<para>The <interfacename>BeanWrapper</interfacename> is a fundamental concept in the
|
||||
Spring Framework and is used in a lot of places. However, you probably
|
||||
will not ever have the need to use the <interfacename>BeanWrapper</interfacename> directly. Because this
|
||||
is reference documentation however, we felt that some explanation might be
|
||||
in order. We're explaining the <interfacename>BeanWrapper</interfacename> in this chapter since if you were
|
||||
going to use it at all, you would probably do so when trying to bind
|
||||
data to objects, which is strongly related to the <interfacename>BeanWrapper</interfacename>.</para>
|
||||
|
||||
<para>Spring uses PropertyEditors all over the place. The concept of a
|
||||
<interfacename>PropertyEditor</interfacename> is part of the JavaBeans specification. Just as the
|
||||
<interfacename>BeanWrapper</interfacename>, it's best to explain the use of PropertyEditors in this
|
||||
chapter as well, since it's closely related to the <interfacename>BeanWrapper</interfacename> and the
|
||||
<interfacename>DataBinder</interfacename>.</para>
|
||||
</section>
|
||||
|
||||
<section id="validator">
|
||||
<title>Validation using Spring's <interfacename>Validator</interfacename> interface</title>
|
||||
<para>Spring's features a <interfacename>Validator</interfacename> interface that you can
|
||||
use to validate objects. The <interfacename>Validator</interfacename> interface works using
|
||||
an <interfacename>Errors</interfacename> object so that while validating, validators can report
|
||||
validation failures to the <interfacename>Errors</interfacename> object.</para>
|
||||
<para>Let's consider a small data object:</para>
|
||||
<programlisting><![CDATA[
|
||||
public class Person {
|
||||
|
||||
private String name;
|
||||
private int age;
|
||||
|
||||
]]><lineannotation>// the usual getters and setters...</lineannotation><![CDATA[
|
||||
}]]></programlisting>
|
||||
<para>We're going to provide validation behavior for the <classname>Person</classname>
|
||||
class by implementing the following two methods of the
|
||||
<interfacename>org.springframework.validation.Validator</interfacename> interface:
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><methodname>supports(Class)</methodname> - Can this
|
||||
<interfacename>Validator</interfacename> validate instances of the supplied
|
||||
<classname>Class</classname>?</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><methodname>validate(Object, org.springframework.validation.Errors)</methodname> -
|
||||
validates the given object and in case of validation errors, registers
|
||||
those with the given <interfacename>Errors</interfacename> object</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
Implementing a <interfacename>Validator</interfacename> is fairly straightforward,
|
||||
especially when you know of the <classname>ValidationUtils</classname> helper class
|
||||
that the Spring Framework also provides.</para>
|
||||
<programlisting><![CDATA[public class PersonValidator implements Validator {
|
||||
|
||||
]]><lineannotation>/**
|
||||
* This <interfacename>Validator</interfacename> validates <emphasis role="bold">just</emphasis> <classname>Person</classname> instances
|
||||
*/</lineannotation><![CDATA[
|
||||
public boolean supports(Class clazz) {
|
||||
return Person.class.equals(clazz);
|
||||
}
|
||||
|
||||
public void validate(Object obj, Errors e) {
|
||||
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
|
||||
Person p = (Person) obj;
|
||||
if (p.getAge() < 0) {
|
||||
e.rejectValue("age", "negativevalue");
|
||||
} else if (p.getAge() > 110) {
|
||||
e.rejectValue("age", "too.darn.old");
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>As you can see, the <literal>static</literal> <methodname>rejectIfEmpty(..)</methodname>
|
||||
method on the <classname>ValidationUtils</classname> class is used to reject the
|
||||
<literal>'name'</literal> property if it is <literal>null</literal> or the empty string.
|
||||
Have a look at the Javadoc for the <classname>ValidationUtils</classname> class to see
|
||||
what functionality it provides besides the example shown previously.</para>
|
||||
<para>While it is certainly possible to implement a single
|
||||
<interfacename>Validator</interfacename> class to validate each of the nested objects
|
||||
in a rich object, it may be better to encapsulate the validation logic for each nested
|
||||
class of object in its own <interfacename>Validator</interfacename> implementation. A
|
||||
simple example of a <emphasis>'rich'</emphasis> object would be a
|
||||
<classname>Customer</classname> that is composed of two <classname>String</classname>
|
||||
properties (a first and second name) and a complex <classname>Address</classname> object.
|
||||
<classname>Address</classname> objects may be used independently of
|
||||
<classname>Customer</classname> objects, and so a distinct
|
||||
<classname>AddressValidator</classname> has been implemented. If you want your
|
||||
<classname>CustomerValidator</classname> to reuse the logic contained within the
|
||||
<classname>AddressValidator</classname> class without recourse to copy-n-paste you can
|
||||
dependency-inject or instantiate an <classname>AddressValidator</classname> within your
|
||||
<classname>CustomerValidator</classname>, and use it like so:</para>
|
||||
<programlisting><![CDATA[public class CustomerValidator implements Validator {
|
||||
|
||||
private final Validator addressValidator;
|
||||
|
||||
public CustomerValidator(Validator addressValidator) {
|
||||
if (addressValidator == null) {
|
||||
throw new IllegalArgumentException("The supplied [Validator] is required and must not be null.");
|
||||
}
|
||||
if (!addressValidator.supports(Address.class)) {
|
||||
throw new IllegalArgumentException(
|
||||
"The supplied [Validator] must support the validation of [Address] instances.");
|
||||
}
|
||||
this.addressValidator = addressValidator;
|
||||
}
|
||||
|
||||
]]><lineannotation>/**
|
||||
* This <interfacename>Validator</interfacename> validates <classname>Customer</classname> instances, and any subclasses of <classname>Customer</classname> too
|
||||
*/</lineannotation><![CDATA[
|
||||
public boolean supports(Class clazz) {
|
||||
return Customer.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public void validate(Object target, Errors errors) {
|
||||
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");
|
||||
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");
|
||||
Customer customer = (Customer) target;
|
||||
try {
|
||||
errors.pushNestedPath("address");
|
||||
ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);
|
||||
} finally {
|
||||
errors.popNestedPath();
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Validation errors are reported to the <interfacename>Errors</interfacename>
|
||||
object passed to the validator. In case of Spring Web MVC you can use
|
||||
<literal><spring:bind/></literal> tag to inspect the error messages, but
|
||||
of course you can also inspect the errors object yourself. More information about
|
||||
the methods it offers can be found from the Javadoc.</para>
|
||||
</section>
|
||||
<section id="validation-conversion">
|
||||
<title>Resolving codes to error messages</title>
|
||||
<para>We've talked about databinding and validation. Outputting messages corresponding to
|
||||
validation errors is the last thing we need to discuss. In the example we've shown
|
||||
above, we rejected the <literal>name</literal> and the <literal>age</literal> field.
|
||||
If we're going to output the error messages by using a <interfacename>MessageSource</interfacename>,
|
||||
we will do so using the error code we've given when rejecting the field ('name' and 'age'
|
||||
in this case). When you call (either directly, or indirectly, using for example the
|
||||
<classname>ValidationUtils</classname> class) <literal>rejectValue</literal> or one of
|
||||
the other <literal>reject</literal> methods from the <interfacename>Errors</interfacename>
|
||||
interface, the underlying implementation will not only register the code you've
|
||||
passed in, but also a number of additional error codes. What error codes it registers
|
||||
is determined by the <interfacename>MessageCodesResolver</interfacename> that is used.
|
||||
By default, the <classname>DefaultMessageCodesResolver</classname> is used, which for example
|
||||
not only registers a message with the code you gave, but also messages that include the
|
||||
field name you passed to the reject method. So in case you reject a field using
|
||||
<literal>rejectValue("age", "too.darn.old")</literal>, apart from the
|
||||
<literal>too.darn.old</literal> code, Spring will also register
|
||||
<literal>too.darn.old.age</literal> and <literal>too.darn.old.age.int</literal>
|
||||
(so the first will include the field name and the second will include the type of the
|
||||
field); this is done as a convenience to aid developers in targeting error
|
||||
messages and suchlike.</para>
|
||||
<para>More information on the <interfacename>MessageCodesResolver</interfacename> and the default
|
||||
strategy can be found online with the Javadocs for
|
||||
<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/validation/MessageCodesResolver.html">MessageCodesResolver</ulink>
|
||||
and
|
||||
<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/validation/DefaultMessageCodesResolver.html">DefaultMessageCodesResolver</ulink>
|
||||
respectively.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-beans">
|
||||
<title>Bean manipulation and the <interfacename>BeanWrapper</interfacename></title>
|
||||
|
||||
<para>The <literal>org.springframework.beans</literal> package adheres to
|
||||
the JavaBeans standard provided by Sun. A JavaBean is simply a class with
|
||||
a default no-argument constructor, which follows a naming convention
|
||||
where (by way of an example) a property named <literal>bingoMadness</literal> would have a setter
|
||||
method <methodname>setBingoMadness(..)</methodname> and a getter method <methodname>getBingoMadness()</methodname>.
|
||||
For more information about JavaBeans and the specification, please refer
|
||||
to Sun's website ( <ulink url="http://java.sun.com/products/javabeans/">java.sun.com/products/javabeans</ulink>).</para>
|
||||
|
||||
<para>One quite important class in the beans package is the
|
||||
<interfacename>BeanWrapper</interfacename> interface and its corresponding
|
||||
implementation (<classname>BeanWrapperImpl</classname>). As quoted from the
|
||||
Javadoc, the <interfacename>BeanWrapper</interfacename> offers functionality to set and get property
|
||||
values (individually or in bulk), get property descriptors, and to query
|
||||
properties to determine if they are readable or writable. Also, the
|
||||
<interfacename>BeanWrapper</interfacename> offers support for nested properties, enabling the setting of
|
||||
properties on sub-properties to an unlimited depth. Then, the <interfacename>BeanWrapper</interfacename>
|
||||
supports the ability to add standard JavaBeans
|
||||
<interfacename>PropertyChangeListeners</interfacename> and
|
||||
<interfacename>VetoableChangeListeners</interfacename>, without the need for
|
||||
supporting code in the target class. Last but not least, the <interfacename>BeanWrapper</interfacename>
|
||||
provides support for the setting of indexed properties. The <interfacename>BeanWrapper</interfacename>
|
||||
usually isn't used by application code directly, but by the
|
||||
<interfacename>DataBinder</interfacename> and the
|
||||
<interfacename>BeanFactory</interfacename>.</para>
|
||||
|
||||
<para>The way the <interfacename>BeanWrapper</interfacename> works is partly indicated by its name:
|
||||
<emphasis>it wraps a bean</emphasis> to perform actions on that bean, like
|
||||
setting and retrieving properties.</para>
|
||||
|
||||
<section id="beans-beans-conventions">
|
||||
<title>Setting and getting basic and nested properties</title>
|
||||
|
||||
<para>Setting and getting properties is done using the
|
||||
<literal>setPropertyValue(s)</literal> and
|
||||
<literal>getPropertyValue(s)</literal> methods that both come with a
|
||||
couple of overloaded variants. They're all described in more detail in
|
||||
the Javadoc Spring comes with. What's important to know is that there
|
||||
are a couple of conventions for indicating properties of an object. A
|
||||
couple of examples:</para>
|
||||
<table id="beans-beans-conventions-properties-tbl">
|
||||
<title>Examples of properties</title>
|
||||
|
||||
<tgroup cols="2">
|
||||
<colspec colname="c1" colwidth="1*" />
|
||||
<colspec colname="c2" colwidth="3*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Expression</entry>
|
||||
<entry>Explanation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>name</literal></entry>
|
||||
|
||||
<entry>Indicates the property <literal>name</literal>
|
||||
corresponding to the methods <methodname>getName()</methodname> or
|
||||
<methodname>isName()</methodname> and
|
||||
<methodname>setName(..)</methodname></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>account.name</literal></entry>
|
||||
|
||||
<entry>Indicates the nested property <literal>name</literal>
|
||||
of the property <literal>account</literal> corresponding e.g.
|
||||
to the methods <literal>getAccount().setName()</literal> or
|
||||
<literal>getAccount().getName()</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>account[2]</literal></entry>
|
||||
|
||||
<entry>Indicates the <emphasis>third</emphasis> element of the
|
||||
indexed property <literal>account</literal>. Indexed
|
||||
properties can be of type <literal>array</literal>,
|
||||
<literal>list</literal> or other <emphasis>naturally
|
||||
ordered</emphasis> collection</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>account[COMPANYNAME]</literal></entry>
|
||||
|
||||
<entry>Indicates the value of the map entry indexed by the key
|
||||
<emphasis>COMPANYNAME</emphasis> of the Map property
|
||||
<literal>account</literal></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>Below you'll find some examples of working with the <interfacename>BeanWrapper</interfacename> to
|
||||
get and set properties.</para>
|
||||
|
||||
<para><emphasis>(This next section is not vitally important to you if you're not
|
||||
planning to work with the <interfacename>BeanWrapper</interfacename> directly. If you're
|
||||
just using the <interfacename>DataBinder</interfacename> and the
|
||||
<interfacename>BeanFactory</interfacename> and their out-of-the-box implementation, you
|
||||
should skip ahead to the section about
|
||||
<interfacename>PropertyEditors</interfacename>.)</emphasis></para>
|
||||
|
||||
<para>Consider the following two classes:</para>
|
||||
<programlisting><![CDATA[public class Company {
|
||||
private String name;
|
||||
private Employee managingDirector;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public Employee getManagingDirector() {
|
||||
return this.managingDirector;
|
||||
}
|
||||
public void setManagingDirector(Employee managingDirector) {
|
||||
this.managingDirector = managingDirector;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[public class Employee {
|
||||
private String name;
|
||||
private float salary;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public float getSalary() {
|
||||
return salary;
|
||||
}
|
||||
public void setSalary(float salary) {
|
||||
this.salary = salary;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>The following code snippets show some examples of how to retrieve
|
||||
and manipulate some of the properties of instantiated
|
||||
<literal>Companies</literal> and <literal>Employees</literal>:</para>
|
||||
<programlisting><![CDATA[BeanWrapper company = BeanWrapperImpl(new Company());
|
||||
]]><lineannotation>// setting the company name..</lineannotation><![CDATA[
|
||||
company.setPropertyValue("name", "Some Company Inc.");
|
||||
]]><lineannotation>// ... can also be done like this:</lineannotation><![CDATA[
|
||||
PropertyValue value = new PropertyValue("name", "Some Company Inc.");
|
||||
company.setPropertyValue(value);
|
||||
|
||||
]]><lineannotation>// ok, let's create the director and tie it to the company:</lineannotation><![CDATA[
|
||||
BeanWrapper jim = BeanWrapperImpl(new Employee());
|
||||
jim.setPropertyValue("name", "Jim Stravinsky");
|
||||
company.setPropertyValue("managingDirector", jim.getWrappedInstance());
|
||||
|
||||
]]><lineannotation>// retrieving the salary of the managingDirector through the company</lineannotation><![CDATA[
|
||||
Float salary = (Float) company.getPropertyValue("managingDirector.salary");]]></programlisting>
|
||||
</section>
|
||||
|
||||
<section id="beans-beans-conversion">
|
||||
<title>Built-in <interface>PropertyEditor</interface> implementations</title>
|
||||
|
||||
<para>Spring heavily uses the concept of <literal>PropertyEditors</literal> to effect the conversion
|
||||
between an <classname>Object</classname> and a <classname>String</classname>. If you think about it,
|
||||
it sometimes might be handy to be able to represent properties in a different way than the object itself.
|
||||
For example, a <classname>Date</classname> can be represented in a human readable way (as the
|
||||
<classname>String</classname> '<literal>2007-14-09</literal>'), while we're still able to convert the
|
||||
human readable form back to the original date (or even better: convert any date entered in a human readable
|
||||
form, back to <classname>Date</classname> objects). This behavior can be achieved by
|
||||
<emphasis>registering custom editors</emphasis>, of type <interfacename>java.beans.PropertyEditor</interfacename>.
|
||||
Registering custom editors on a <interfacename>BeanWrapper</interfacename> or alternately in a specific IoC
|
||||
container as mentioned in the previous chapter, gives it the knowledge of how to convert properties to the
|
||||
desired type. Read more about <interfacename>PropertyEditors</interfacename> in the Javadoc of the
|
||||
<literal>java.beans</literal> package provided by Sun.</para>
|
||||
|
||||
<para>A couple of examples where property editing is used in Spring:
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><emphasis>setting properties on beans</emphasis> is done
|
||||
using <literal>PropertyEditors</literal>. When mentioning
|
||||
<literal>java.lang.String</literal> as the value of a property of
|
||||
some bean you're declaring in XML file, Spring will (if the setter
|
||||
of the corresponding property has a <classname>Class</classname>-parameter) use the
|
||||
<classname>ClassEditor</classname> to try to resolve the parameter to
|
||||
a <classname>Class</classname> object.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis>parsing HTTP request parameters</emphasis> in
|
||||
Spring's MVC framework is done using all kinds of <literal>PropertyEditors</literal>
|
||||
that you can manually bind in all subclasses of the
|
||||
<classname>CommandController</classname>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>Spring has a number of built-in <literal>PropertyEditors</literal> to make life easy.
|
||||
Each of those is listed below and they are all located in the
|
||||
<literal>org.springframework.beans.propertyeditors</literal> package. Most, but not all (as indicated below),
|
||||
are registered by default by <classname>BeanWrapperImpl</classname>. Where the property editor is configurable
|
||||
in some fashion, you can of course still register your own variant to override the default one:</para>
|
||||
|
||||
<table id="beans-beans-property-editors-tbl">
|
||||
<title>Built-in <literal>PropertyEditors</literal></title>
|
||||
|
||||
<tgroup cols="2">
|
||||
<colspec colname="c1" colwidth="3*" />
|
||||
<colspec colname="c2" colwidth="5*" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Class</entry>
|
||||
<entry>Explanation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><classname>ByteArrayPropertyEditor</classname></entry>
|
||||
|
||||
<entry>Editor for byte arrays. Strings will simply be
|
||||
converted to their corresponding byte representations.
|
||||
Registered by default by <classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>ClassEditor</classname></entry>
|
||||
|
||||
<entry>Parses Strings representing classes to actual classes
|
||||
and the other way around. When a class is not found, an
|
||||
<classname>IllegalArgumentException</classname> is thrown. Registered by default by
|
||||
<classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>CustomBooleanEditor</classname></entry>
|
||||
|
||||
<entry>Customizable property editor for <classname>Boolean</classname> properties.
|
||||
Registered by default by <classname>BeanWrapperImpl</classname>, but, can be
|
||||
overridden by registering custom instance of it as custom
|
||||
editor.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><classname>CustomCollectionEditor</classname></entry>
|
||||
<entry>Property editor for Collections, converting any source
|
||||
<interfacename>Collection</interfacename> to a given target <interfacename>Collection</interfacename> type.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><classname>CustomDateEditor</classname></entry>
|
||||
|
||||
<entry>Customizable property editor for java.util.Date,
|
||||
supporting a custom DateFormat. NOT registered by default. Must
|
||||
be user registered as needed with appropriate format.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>CustomNumberEditor</classname></entry>
|
||||
|
||||
<entry>Customizable property editor for any Number subclass
|
||||
like <classname>Integer</classname>, <classname>Long</classname>,
|
||||
<classname>Float</classname>, <classname>Double</classname>. Registered
|
||||
by default by <classname>BeanWrapperImpl</classname>, but can be
|
||||
overridden by registering custom instance of it as a custom editor.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>FileEditor</classname></entry>
|
||||
|
||||
<entry>Capable of resolving Strings to
|
||||
<classname>java.io.File</classname> objects. Registered by default by
|
||||
<classname>BeanWrapperImpl</classname>. </entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>InputStreamEditor</classname></entry>
|
||||
|
||||
<entry>One-way property editor, capable of taking a text
|
||||
string and producing (via an intermediate <classname>ResourceEditor</classname> and
|
||||
<interfacename>Resource</interfacename>) an
|
||||
<interfacename>InputStream</interfacename>, so <interfacename>InputStream</interfacename>
|
||||
properties may be directly set as Strings. Note that the default usage
|
||||
will not close the <interfacename>InputStream</interfacename> for
|
||||
you! Registered by default by <classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>LocaleEditor</classname></entry>
|
||||
|
||||
<entry>Capable of resolving Strings to
|
||||
<classname>Locale</classname> objects and vice versa (the String
|
||||
format is [language]_[country]_[variant], which is the same
|
||||
thing the toString() method of Locale provides). Registered by
|
||||
default by <classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>PatternEditor</classname></entry>
|
||||
|
||||
<entry>Capable of resolving Strings to JDK 1.5
|
||||
<classname>Pattern</classname> objects and vice versa.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>PropertiesEditor</classname></entry>
|
||||
|
||||
<entry>Capable of converting Strings (formatted using the
|
||||
format as defined in the Javadoc for the java.lang.Properties
|
||||
class) to <classname>Properties</classname> objects. Registered by
|
||||
default by <classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>StringTrimmerEditor</classname></entry>
|
||||
|
||||
<entry>Property editor that trims Strings. Optionally allows
|
||||
transforming an empty string into a <literal>null</literal> value. NOT
|
||||
registered by default; must be user registered as needed.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>URLEditor</classname></entry>
|
||||
|
||||
<entry>Capable of resolving a String representation of a URL
|
||||
to an actual <classname>URL</classname> object. Registered by
|
||||
default by <classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
Spring uses the <interfacename>java.beans.PropertyEditorManager</interfacename> to set
|
||||
the search path for property editors that might be needed. The search path also includes
|
||||
<literal>sun.bean.editors</literal>, which includes
|
||||
<interfacename>PropertyEditor</interfacename> implementations for types such as
|
||||
<classname>Font</classname>, <classname>Color</classname>, and most of the primitive types.
|
||||
Note also that the standard JavaBeans infrastructure will automatically discover
|
||||
<interfacename>PropertyEditor</interfacename> classes (without you having to register them
|
||||
explicitly) if they are in the same package as the class they handle, and have the same name
|
||||
as that class, with <literal>'Editor'</literal> appended; for example, one could have the
|
||||
following class and package structure, which would be sufficient for the
|
||||
<classname>FooEditor</classname> class to be recognized and used as the
|
||||
<interfacename>PropertyEditor</interfacename> for <classname>Foo</classname>-typed
|
||||
properties.
|
||||
</para>
|
||||
<programlisting><![CDATA[com
|
||||
chank
|
||||
pop
|
||||
Foo
|
||||
FooEditor ]]><lineannotation>// the <interfacename>PropertyEditor</interfacename> for the <classname>Foo</classname> class</lineannotation></programlisting>
|
||||
<para>Note that you can also use the standard <interfacename>BeanInfo</interfacename> JavaBeans
|
||||
mechanism here as well (described
|
||||
<ulink url="http://java.sun.com/docs/books/tutorial/javabeans/customization/index.html">in not-amazing-detail here</ulink>).
|
||||
Find below an example of using the <interfacename>BeanInfo</interfacename> mechanism for
|
||||
explicitly registering one or more <interfacename>PropertyEditor</interfacename> instances
|
||||
with the properties of an associated class.</para>
|
||||
<programlisting><![CDATA[com
|
||||
chank
|
||||
pop
|
||||
Foo
|
||||
FooBeanInfo ]]><lineannotation>// the <interfacename>BeanInfo</interfacename> for the <classname>Foo</classname> class</lineannotation></programlisting>
|
||||
<para>
|
||||
Here is the Java source code for the referenced <classname>FooBeanInfo</classname> class. This
|
||||
would associate a <classname>CustomNumberEditor</classname> with the <literal>age</literal>
|
||||
property of the <classname>Foo</classname> class.
|
||||
</para>
|
||||
<programlisting><![CDATA[public class FooBeanInfo extends SimpleBeanInfo {
|
||||
|
||||
public PropertyDescriptor[] getPropertyDescriptors() {
|
||||
try {
|
||||
final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true);
|
||||
PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) {
|
||||
public PropertyEditor createPropertyEditor(Object bean) {
|
||||
return numberPE;
|
||||
};
|
||||
};
|
||||
return new PropertyDescriptor[] { ageDescriptor };
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
throw new Error(ex.toString());
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
|
||||
<section id="beans-beans-conversion-customeditor-registration">
|
||||
<title>Registering additional custom <interfacename>PropertyEditors</interfacename></title>
|
||||
|
||||
<para>When setting bean properties as a string value, a Spring IoC container
|
||||
ultimately uses standard JavaBeans <literal>PropertyEditors</literal> to convert these
|
||||
Strings to the complex type of the property. Spring pre-registers a number
|
||||
of custom <literal>PropertyEditors</literal> (for example, to convert a classname expressed
|
||||
as a string into a real <classname>Class</classname> object). Additionally, Java's standard
|
||||
JavaBeans <interfacename>PropertyEditor</interfacename> lookup mechanism allows a
|
||||
<classname>PropertyEditor</classname> for a class simply to be named appropriately and
|
||||
placed in the same package as the class it provides support for, to be found automatically.</para>
|
||||
<para>If there is a need to register other custom <literal>PropertyEditors</literal>, there
|
||||
are several mechanisms available. The most manual approach, which is not normally convenient or
|
||||
recommended, is to simply use the <methodname>registerCustomEditor()</methodname> method of the
|
||||
<interfacename>ConfigurableBeanFactory</interfacename> interface, assuming you have a
|
||||
<interfacename>BeanFactory</interfacename> reference. Another, slightly more convenient, mechanism is to use
|
||||
a special bean factory post-processor called <classname>CustomEditorConfigurer</classname>.
|
||||
Although bean factory post-processors can be used with <interfacename>BeanFactory</interfacename>
|
||||
implementations, the <classname>CustomEditorConfigurer</classname> has a nested property setup, so it is
|
||||
strongly recommended that it is used with the <interfacename>ApplicationContext</interfacename>, where
|
||||
it may be deployed in similar fashion to any other bean, and automatically detected and applied.</para>
|
||||
<para>Note that all bean factories and application contexts automatically use a number of built-in property
|
||||
editors, through their use of something called a <interfacename>BeanWrapper</interfacename> to handle
|
||||
property conversions. The standard property editors that the <interfacename>BeanWrapper</interfacename>
|
||||
registers are listed in <link linkend="beans-beans-conversion">the previous section</link>. Additionally,
|
||||
<literal>ApplicationContexts</literal> also override or add an additional number of editors
|
||||
to handle resource lookups in a manner appropriate to the specific application context type.</para>
|
||||
|
||||
<para>Standard JavaBeans <interfacename>PropertyEditor</interfacename> instances are used to convert
|
||||
property values expressed as strings to the actual complex type of the property.
|
||||
<classname>CustomEditorConfigurer</classname>, a bean factory post-processor, may be used to conveniently
|
||||
add support for additional <interfacename>PropertyEditor</interfacename> instances to an
|
||||
<interfacename>ApplicationContext</interfacename>.</para>
|
||||
<para>Consider a user class <classname>ExoticType</classname>, and another class
|
||||
<classname>DependsOnExoticType</classname> which needs <classname>ExoticType</classname> set as a property:</para>
|
||||
|
||||
<programlisting><![CDATA[package example;
|
||||
|
||||
public class ExoticType {
|
||||
|
||||
private String name;
|
||||
|
||||
public ExoticType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public class DependsOnExoticType {
|
||||
|
||||
private ExoticType type;
|
||||
|
||||
public void setType(ExoticType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>When things are properly set up, we want to be able to assign the type property as a string, which a
|
||||
<interfacename>PropertyEditor</interfacename> will behind the scenes convert into an actual
|
||||
<classname>ExoticType</classname> instance:</para>
|
||||
<programlisting><![CDATA[<bean id="sample" class="example.DependsOnExoticType">
|
||||
<property name="type" value="aNameForExoticType"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>The <interfacename>PropertyEditor</interfacename> implementation could look similar to this:</para>
|
||||
<programlisting><lineannotation>// converts string representation to <classname>ExoticType</classname> object</lineannotation><![CDATA[
|
||||
package example;
|
||||
|
||||
public class ExoticTypeEditor extends PropertyEditorSupport {
|
||||
|
||||
private String format;
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public void setAsText(String text) {
|
||||
if (format != null && format.equals("upperCase")) {
|
||||
text = text.toUpperCase();
|
||||
}
|
||||
ExoticType type = new ExoticType(text);
|
||||
setValue(type);
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Finally, we use <classname>CustomEditorConfigurer</classname> to register the new
|
||||
<interfacename>PropertyEditor</interfacename> with the <interfacename>ApplicationContext</interfacename>,
|
||||
which will then be able to use it as needed:</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
||||
<property name="customEditors">
|
||||
<map>
|
||||
<entry key="example.ExoticType">
|
||||
<bean class="example.ExoticTypeEditor">
|
||||
<property name="format" value="upperCase"/>
|
||||
</bean>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
<section id="beans-beans-conversion-customeditor-registration-per">
|
||||
<title>Using <interfacename>PropertyEditorRegistrars</interfacename></title>
|
||||
|
||||
<para>Another mechanism for registering property editors with the Spring container is to create and use
|
||||
a <interfacename>PropertyEditorRegistrar</interfacename>. This interface is particularly useful when you
|
||||
need to use the same set of property editors in several different situations: write a corresponding
|
||||
registrar and reuse that in each case. <literal>PropertyEditorRegistrars</literal> work in conjunction
|
||||
with an interface called <interfacename>PropertyEditorRegistry</interfacename>, an interface
|
||||
that is implemented by the Spring <interfacename>BeanWrapper</interfacename> (and
|
||||
<interfacename>DataBinder</interfacename>). <literal>PropertyEditorRegistrars</literal> are particularly
|
||||
convenient when used in conjunction with the <classname>CustomEditorConfigurer</classname>
|
||||
(introduced <link linkend="beans-beans-conversion-customeditor-registration">here</link>), which exposes a
|
||||
property called <methodname>setPropertyEditorRegistrars(..)</methodname>:
|
||||
<literal>PropertyEditorRegistrars</literal> added to a <classname>CustomEditorConfigurer</classname> in this
|
||||
fashion can easily be shared with <interfacename>DataBinder</interfacename> and Spring MVC
|
||||
<interfacename>Controllers</interfacename>. Furthermore, it avoids the need for synchronization on custom
|
||||
editors: a <interfacename>PropertyEditorRegistrar</interfacename> is expected to create fresh
|
||||
<interfacename>PropertyEditor</interfacename> instances for each bean creation attempt.</para>
|
||||
<para>Using a <interfacename>PropertyEditorRegistrar</interfacename> is perhaps best illustrated with an
|
||||
example. First off, you need to create your own <interfacename>PropertyEditorRegistrar</interfacename>
|
||||
implementation:</para>
|
||||
|
||||
<programlisting><![CDATA[package com.foo.editors.spring;
|
||||
|
||||
public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
|
||||
|
||||
public void registerCustomEditors(PropertyEditorRegistry registry) {
|
||||
|
||||
]]><lineannotation>// it is expected that new <interfacename>PropertyEditor</interfacename> instances are created</lineannotation><![CDATA[
|
||||
registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());
|
||||
|
||||
]]><lineannotation>// you could register as many custom property editors as are required here...</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>See also the <classname>org.springframework.beans.support.ResourceEditorRegistrar</classname> for an
|
||||
example <interfacename>PropertyEditorRegistrar</interfacename> implementation. Notice how in its
|
||||
implementation of the <methodname>registerCustomEditors(..)</methodname> method it creates new instances
|
||||
of each property editor.</para>
|
||||
<para>Next we configure a <classname>CustomEditorConfigurer</classname> and inject an
|
||||
instance of our <classname>CustomPropertyEditorRegistrar</classname> into it:</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
||||
<property name="propertyEditorRegistrars">
|
||||
<list>
|
||||
<ref bean="customPropertyEditorRegistrar"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="customPropertyEditorRegistrar" class="com.foo.editors.spring.CustomPropertyEditorRegistrar"/>]]></programlisting>
|
||||
|
||||
<para>Finally, and in a bit of a departure from the focus of this chapter, for those of you using
|
||||
<link linkend="mvc">Spring's MVC web framework</link>, using <interfacename>PropertyEditorRegistrars</interfacename>
|
||||
in conjunction with data-binding <interfacename>Controllers</interfacename> (such as
|
||||
<classname>SimpleFormController</classname>) can be very convenient. Find below an example of using a
|
||||
<interfacename>PropertyEditorRegistrar</interfacename> in the implementation of an <methodname>initBinder(..)</methodname>
|
||||
method:</para>
|
||||
|
||||
<programlisting><![CDATA[public final class RegisterUserController extends SimpleFormController {
|
||||
|
||||
private final PropertyEditorRegistrar customPropertyEditorRegistrar;
|
||||
|
||||
public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) {
|
||||
this.customPropertyEditorRegistrar = propertyEditorRegistrar;
|
||||
}
|
||||
|
||||
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
|
||||
]]><emphasis role="bold">this.customPropertyEditorRegistrar.registerCustomEditors(binder);</emphasis><![CDATA[
|
||||
}
|
||||
|
||||
]]><lineannotation>// other methods to do with registering a <classname>User</classname></lineannotation><![CDATA[
|
||||
}]]></programlisting>
|
||||
|
||||
<para>This style of <interfacename>PropertyEditor</interfacename> registration can lead to concise code (the
|
||||
implementation of <methodname>initBinder(..)</methodname> is just one line long!), and allows common
|
||||
<interfacename>PropertyEditor</interfacename> registration code to be encapsulated in a class and then
|
||||
shared amongst as many <interfacename>Controllers</interfacename> as needed.</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,597 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<appendix id="extensible-xml">
|
||||
<title>Extensible XML authoring</title>
|
||||
<section id="extensible-xml-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>Since version 2.0, Spring has featured a mechanism for schema-based extensions
|
||||
to the basic Spring XML format for defining and configuring beans. This section is
|
||||
devoted to detailing how you would go about writing your own custom XML bean definition
|
||||
parsers and integrating such parsers into the Spring IoC container.</para>
|
||||
<para>To facilitate the authoring of configuration files using a schema-aware XML editor,
|
||||
Spring's extensible XML configuration mechanism is based on XML Schema. If you are
|
||||
not familiar with Spring's current XML configuration extensions that come with the
|
||||
standard Spring distribution, please first read the appendix entitled
|
||||
<xref linkend="xsd-config"/>.</para>
|
||||
<para>Creating new XML configuration extensions can be done by following these (relatively)
|
||||
simple steps:</para>
|
||||
<para>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem>
|
||||
<para><link linkend="extensible-xml-schema">Authoring</link> an XML schema to describe your custom element(s).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="extensible-xml-namespacehandler">Coding</link> a custom <interfacename>NamespaceHandler</interfacename>
|
||||
implementation (this is an easy step, don't worry).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="extensible-xml-parser">Coding</link> one or more <interfacename>BeanDefinitionParser</interfacename>
|
||||
implementations (this is where the real work is done).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="extensible-xml-registration">Registering</link> the above artifacts with Spring (this too is an easy step).</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>What follows is a description of each of these steps. For the example, we will create
|
||||
an XML extension (a custom XML element) that allows us to configure objects of the type
|
||||
<classname>SimpleDateFormat</classname> (from the <literal>java.text</literal> package)
|
||||
in an easy manner. When we are done, we will be able to define bean definitions of type
|
||||
<classname>SimpleDateFormat</classname> like this:</para>
|
||||
<programlisting><![CDATA[<myns:dateformat id="dateFormat"
|
||||
pattern="yyyy-MM-dd HH:mm"
|
||||
lenient="true"/>
|
||||
]]></programlisting>
|
||||
<para><emphasis>(Don't worry about the fact that this example is very simple; much more
|
||||
detailed examples follow afterwards. The intent in this first simple example is to walk
|
||||
you through the basic steps involved.)</emphasis></para>
|
||||
</section>
|
||||
<section id="extensible-xml-schema">
|
||||
<title>Authoring the schema</title>
|
||||
<para>Creating an XML configuration extension for use with Spring's IoC container
|
||||
starts with authoring an XML Schema to describe the extension. What follows
|
||||
is the schema we'll use to configure <classname>SimpleDateFormat</classname>
|
||||
objects.</para>
|
||||
<programlisting><lineannotation><!-- myns.xsd (inside package org/springframework/samples/xml) --></lineannotation><![CDATA[
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns="http://www.mycompany.com/schema/myns"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
targetNamespace="http://www.mycompany.com/schema/myns"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
|
||||
|
||||
<xsd:element name="dateformat">
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>]]>
|
||||
<emphasis role="bold"><![CDATA[<xsd:extension base="beans:identifiedType">]]></emphasis><![CDATA[
|
||||
<xsd:attribute name="lenient" type="xsd:boolean"/>
|
||||
<xsd:attribute name="pattern" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:schema>]]></programlisting>
|
||||
<para>(The emphasized line contains an extension base for all tags that
|
||||
will be identifiable (meaning they have an <literal>id</literal> attribute
|
||||
that will be used as the bean identifier in the container). We are able to use this
|
||||
attribute because we imported the Spring-provided <literal>'beans'</literal>
|
||||
namespace.)</para>
|
||||
<para>The above schema will be used to configure <classname>SimpleDateFormat</classname>
|
||||
objects, directly in an XML application context file using the
|
||||
<literal><myns:dateformat/></literal> element.</para>
|
||||
<programlisting><![CDATA[<myns:dateformat id="dateFormat"
|
||||
pattern="yyyy-MM-dd HH:mm"
|
||||
lenient="true"/>
|
||||
]]></programlisting>
|
||||
<para>Note that after we've created the infrastructure classes, the above snippet of XML
|
||||
will essentially be exactly the same as the following XML snippet. In other words,
|
||||
we're just creating a bean in the container, identified by the name
|
||||
<literal>'dateFormat'</literal> of type <classname>SimpleDateFormat</classname>, with a
|
||||
couple of properties set.</para>
|
||||
<programlisting><![CDATA[<bean id="dateFormat" class="java.text.SimpleDateFormat">
|
||||
<constructor-arg value="yyyy-HH-dd HH:mm"/>
|
||||
<property name="lenient" value="true"/>
|
||||
</bean>]]></programlisting>
|
||||
<note>
|
||||
<para>The schema-based approach to creating configuration format allows for
|
||||
tight integration with an IDE that has a schema-aware XML editor. Using a properly
|
||||
authored schema, you can use autocompletion to have a user choose between several
|
||||
configuration options defined in the enumeration.</para>
|
||||
</note>
|
||||
</section>
|
||||
<section id="extensible-xml-namespacehandler">
|
||||
<title>Coding a <interfacename>NamespaceHandler</interfacename></title>
|
||||
<para>In addition to the schema, we need a <interfacename>NamespaceHandler</interfacename>
|
||||
that will parse all elements of this specific namespace Spring encounters
|
||||
while parsing configuration files. The <interfacename>NamespaceHandler</interfacename>
|
||||
should in our case take care of the parsing of the <literal>myns:dateformat</literal>
|
||||
element.</para>
|
||||
<para>The <interfacename>NamespaceHandler</interfacename> interface is pretty simple in that
|
||||
it features just three methods:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><methodname>init()</methodname> - allows for initialization of
|
||||
the <interfacename>NamespaceHandler</interfacename> and will be called by Spring
|
||||
before the handler is used</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><methodname>BeanDefinition parse(Element, ParserContext)</methodname> -
|
||||
called when Spring encounters a top-level element (not nested inside a bean definition
|
||||
or a different namespace). This method can register bean definitions itself and/or
|
||||
return a bean definition.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><methodname>BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext)</methodname> -
|
||||
called when Spring encounters an attribute or nested element of a different namespace.
|
||||
The decoration of one or more bean definitions is used for example with the
|
||||
<link linkend="beans-factory-scopes">out-of-the-box scopes Spring 2.0 supports</link>.
|
||||
We'll start by highlighting a simple example, without using decoration, after which
|
||||
we will show decoration in a somewhat more advanced example.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>Although it is perfectly possible to code your own
|
||||
<interfacename>NamespaceHandler</interfacename> for the entire namespace
|
||||
(and hence provide code that parses each and every element in the namespace),
|
||||
it is often the case that each top-level XML element in a Spring XML
|
||||
configuration file results in a single bean definition (as in our
|
||||
case, where a single <literal><myns:dateformat/></literal> element
|
||||
results in a single <classname>SimpleDateFormat</classname> bean definition).
|
||||
Spring features a number of convenience classes that support this scenario.
|
||||
In this example, we'll make use the <classname>NamespaceHandlerSupport</classname> class:</para>
|
||||
<programlisting><![CDATA[package org.springframework.samples.xml;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
public class MyNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {]]><emphasis role="bold"><![CDATA[
|
||||
registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
|
||||
]]></emphasis>}
|
||||
}</programlisting>
|
||||
<para>The observant reader will notice that there isn't actually a whole lot of
|
||||
parsing logic in this class. Indeed... the <classname>NamespaceHandlerSupport</classname>
|
||||
class has a built in notion of delegation. It supports the registration of any number
|
||||
of <interfacename>BeanDefinitionParser</interfacename> instances, to which it will delegate
|
||||
to when it needs to parse an element in its namespace. This clean separation of concerns
|
||||
allows a <interfacename>NamespaceHandler</interfacename> to handle the orchestration
|
||||
of the parsing of <emphasis>all</emphasis> of the custom elements in its namespace,
|
||||
while delegating to <literal>BeanDefinitionParsers</literal> to do the grunt work of the
|
||||
XML parsing; this means that each <interfacename>BeanDefinitionParser</interfacename> will
|
||||
contain just the logic for parsing a single custom element, as we can see in the next step</para>
|
||||
</section>
|
||||
<section id="extensible-xml-parser">
|
||||
<title>Coding a <interfacename>BeanDefinitionParser</interfacename></title>
|
||||
<para>A <interfacename>BeanDefinitionParser</interfacename> will be used if the
|
||||
<interfacename>NamespaceHandler</interfacename> encounters an XML element of the type
|
||||
that has been mapped to the specific bean definition parser (which is <literal>'dateformat'</literal>
|
||||
in this case). In other words, the <interfacename>BeanDefinitionParser</interfacename> is
|
||||
responsible for parsing <emphasis>one</emphasis> distinct top-level XML element defined in the
|
||||
schema. In the parser, we'll have access to the XML element (and thus its subelements too)
|
||||
so that we can parse our custom XML content, as can be seen in the following example:</para>
|
||||
<programlisting><![CDATA[package org.springframework.samples.xml;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { ]]><co id="extensible-xml-parser-simpledateformat-co-1"/><![CDATA[
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return SimpleDateFormat.class; ]]><co id="extensible-xml-parser-simpledateformat-co-2"/><![CDATA[
|
||||
}
|
||||
|
||||
protected void doParse(Element element, BeanDefinitionBuilder bean) {
|
||||
]]><lineannotation>// this will never be null since the schema explicitly requires that a value be supplied</lineannotation><![CDATA[
|
||||
String pattern = element.getAttribute("pattern");
|
||||
bean.addConstructorArg(pattern);
|
||||
|
||||
]]><lineannotation>// this however is an optional property</lineannotation><![CDATA[
|
||||
String lenient = element.getAttribute("lenient");
|
||||
if (StringUtils.hasText(lenient)) {
|
||||
bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
<calloutlist>
|
||||
<callout arearefs="extensible-xml-parser-simpledateformat-co-1">
|
||||
<para>We use the Spring-provided <classname>AbstractSingleBeanDefinitionParser</classname>
|
||||
to handle a lot of the basic grunt work of creating a <emphasis>single</emphasis>
|
||||
<interfacename>BeanDefinition</interfacename>.</para>
|
||||
</callout>
|
||||
<callout arearefs="extensible-xml-parser-simpledateformat-co-2">
|
||||
<para>We supply the <classname>AbstractSingleBeanDefinitionParser</classname> superclass
|
||||
with the type that our single <interfacename>BeanDefinition</interfacename> will represent.</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
<para>In this simple case, this is all that we need to do. The creation of our single
|
||||
<interfacename>BeanDefinition</interfacename> is handled by the <classname>AbstractSingleBeanDefinitionParser</classname>
|
||||
superclass, as is the extraction and setting of the bean definition's unique identifier.</para>
|
||||
</section>
|
||||
<section id="extensible-xml-registration">
|
||||
<title>Registering the handler and the schema</title>
|
||||
<para>The coding is finished! All that remains to be done is to somehow make the Spring XML
|
||||
parsing infrastructure aware of our custom element; we do this by registering our custom
|
||||
<interfacename>namespaceHandler</interfacename> and custom XSD file in two special purpose
|
||||
properties files. These properties files are both placed in a
|
||||
<filename class="directory">'META-INF'</filename> directory in your application, and can, for
|
||||
example, be distributed alongside your binary classes in a JAR file. The Spring XML parsing
|
||||
infrastructurewill automatically pick up your new extension by consuming these special
|
||||
properties files, the formats of which are detailed below.</para>
|
||||
<section id="extensible-xml-registration-spring-handlers">
|
||||
<title><filename>'META-INF/spring.handlers'</filename></title>
|
||||
<para>The properties file called <filename>'spring.handlers'</filename> contains a mapping
|
||||
of XML Schema URIs to namespace handler classes. So for our example, we need to write the
|
||||
following:</para>
|
||||
<programlisting><![CDATA[http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler]]></programlisting>
|
||||
<para><emphasis>(The <literal>':'</literal> character is a valid delimiter in the Java properties format,
|
||||
and so the <literal>':'</literal> character in the URI needs to be escaped with a backslash.)</emphasis></para>
|
||||
<para>The first part (the key) of the key-value pair is the URI associated with your custom namespace
|
||||
extension, and needs to <emphasis>match exactly</emphasis> the value of the
|
||||
<literal>'targetNamespace'</literal> attribute as specified in your custom XSD schema.</para>
|
||||
</section>
|
||||
<section id="extensible-xml-registration-spring-schemas">
|
||||
<title><filename>'META-INF/spring.schemas'</filename></title>
|
||||
<para>The properties file called <filename>'spring.schemas'</filename> contains a mapping
|
||||
of XML Schema locations (referred to along with the schema declaration in XML files
|
||||
that use the schema as part of the <literal>'xsi:schemaLocation'</literal> attribute)
|
||||
to <emphasis>classpath</emphasis> resources. This file is needed to prevent Spring from
|
||||
absolutely having to use a default <interfacename>EntityResolver</interfacename> that requires
|
||||
Internet access to retrieve the schema file. If you specify the mapping in this properties file,
|
||||
Spring will search for the schema on the classpath (in this case <literal>'myns.xsd'</literal>
|
||||
in the <literal>'org.springframework.samples.xml'</literal> package):</para>
|
||||
<programlisting><![CDATA[http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd]]></programlisting>
|
||||
<para>The upshot of this is that you are encouraged to deploy your XSD file(s) right alongside
|
||||
the <interfacename>NamespaceHandler</interfacename> and <interfacename>BeanDefinitionParser</interfacename>
|
||||
classes on the classpath.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="extensible-xml-using">
|
||||
<title>Using a custom extension in your Spring XML configuration</title>
|
||||
<para>Using a custom extension that you yourself have implemented is no different from
|
||||
using one of the 'custom' extensions that Spring provides straight out of the box. Find below
|
||||
an example of using the custom <literal><dateformat/></literal> element developed in the
|
||||
previous steps in a Spring XML configuration file.</para>
|
||||
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:myns="http://www.mycompany.com/schema/myns"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd">
|
||||
|
||||
]]><lineannotation><!-- as a top-level bean --></lineannotation><![CDATA[
|
||||
<myns:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm" lenient="true"/>
|
||||
|
||||
<bean id="jobDetailTemplate" abstract="true">
|
||||
<property name="dateFormat">
|
||||
]]><lineannotation><!-- as an inner bean --></lineannotation><![CDATA[
|
||||
<myns:dateformat pattern="HH:mm MM-dd-yyyy"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
<section id="extensible-xml-meat">
|
||||
<title>Meatier examples</title>
|
||||
<para>Find below some much meatier examples of custom XML extensions.</para>
|
||||
<section id="extensible-xml-custom-nested">
|
||||
<title>Nesting custom tags within custom tags</title>
|
||||
<para>This example illustrates how you might go about writing the various artifacts
|
||||
required to satisfy a target of the following configuration:</para>
|
||||
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:foo="http://www.foo.com/schema/component"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.foo.com/schema/component http://www.foo.com/schema/component/component.xsd">
|
||||
|
||||
]]><lineannotation><![CDATA[<foo:component id="bionic-family" name="Bionic-1">
|
||||
<foo:component name="Sport-1"/>
|
||||
<foo:component name="Rock-1"/>
|
||||
</foo:component>]]></lineannotation><![CDATA[
|
||||
|
||||
</beans>]]></programlisting>
|
||||
<para>The above configuration actually nests custom extensions within each other. The class
|
||||
that is actually configured by the above <literal><foo:component/></literal>
|
||||
element is the <classname>Component</classname> class (shown directly below). Notice
|
||||
how the <classname>Component</classname> class does <emphasis>not</emphasis> expose
|
||||
a setter method for the <literal>'components'</literal> property; this makes it hard
|
||||
(or rather impossible) to configure a bean definition for the <classname>Component</classname>
|
||||
class using setter injection.</para>
|
||||
<programlisting><![CDATA[package com.foo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Component {
|
||||
|
||||
private String name;
|
||||
private List components = new ArrayList();
|
||||
|
||||
]]><lineannotation>// mmm, there is no setter method for the <literal>'components'</literal></lineannotation><![CDATA[
|
||||
public void addComponent(Component component) {
|
||||
this.components.add(component);
|
||||
}
|
||||
|
||||
public List getComponents() {
|
||||
return components;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>The typical solution to this issue is to create a custom <interfacename>FactoryBean</interfacename>
|
||||
that exposes a setter property for the <literal>'components'</literal> property.</para>
|
||||
<programlisting><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class ComponentFactoryBean implements FactoryBean {
|
||||
|
||||
private Component parent;
|
||||
private List children;
|
||||
|
||||
public void setParent(Component parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void setChildren(List children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
if (this.children != null && this.children.size() > 0) {
|
||||
for (Iterator it = children.iterator(); it.hasNext();) {
|
||||
Component childComponent = (Component) it.next();
|
||||
this.parent.addComponent(childComponent);
|
||||
}
|
||||
}
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return Component.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>This is all very well, and does work nicely, but exposes a lot of Spring plumbing to the
|
||||
end user. What we are going to do is write a custom extension that hides away all of this
|
||||
Spring plumbing. If we stick to <link linkend="extensible-xml-introduction">the steps described
|
||||
previously</link>, we'll start off by creating the XSD schema to define the structure of
|
||||
our custom tag.</para>
|
||||
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
|
||||
<xsd:schema xmlns="http://www.foo.com/schema/component"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.foo.com/schema/component"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:element name="component">
|
||||
<xsd:complexType>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element ref="component"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="id" type="xsd:ID"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:schema>
|
||||
]]></programlisting>
|
||||
<para>We'll then create a custom <interfacename>NamespaceHandler</interfacename>.</para>
|
||||
<programlisting><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
public class ComponentNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("component", new ComponentBeanDefinitionParser());
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Next up is the custom <interfacename>BeanDefinitionParser</interfacename>. Remember
|
||||
that what we are creating is a <interfacename>BeanDefinition</interfacename> describing
|
||||
a <classname>ComponentFactoryBean</classname>.</para>
|
||||
<programlisting><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(ComponentFactoryBean.class);
|
||||
BeanDefinitionBuilder parent = parseComponent(element);
|
||||
factory.addPropertyValue("parent", parent.getBeanDefinition());
|
||||
|
||||
List childElements = DomUtils.getChildElementsByTagName(element, "component");
|
||||
if (childElements != null && childElements.size() > 0) {
|
||||
parseChildComponents(childElements, factory);
|
||||
}
|
||||
return factory.getBeanDefinition();
|
||||
}
|
||||
|
||||
private static BeanDefinitionBuilder parseComponent(Element element) {
|
||||
BeanDefinitionBuilder component = BeanDefinitionBuilder.rootBeanDefinition(Component.class);
|
||||
component.addPropertyValue("name", element.getAttribute("name"));
|
||||
return component;
|
||||
}
|
||||
|
||||
private static void parseChildComponents(List childElements, BeanDefinitionBuilder factory) {
|
||||
ManagedList children = new ManagedList(childElements.size());
|
||||
for (int i = 0; i < childElements.size(); ++i) {
|
||||
Element childElement = (Element) childElements.get(i);
|
||||
BeanDefinitionBuilder child = parseComponent(childElement);
|
||||
children.add(child.getBeanDefinition());
|
||||
}
|
||||
factory.addPropertyValue("children", children);
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Lastly, the various artifacts need to be registered with the Spring XML infrastructure.</para>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.handlers'</filename></lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler]]></programlisting>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.schemas'</filename></lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd]]></programlisting>
|
||||
</section>
|
||||
<section id="extensible-xml-custom-just-attributes">
|
||||
<title>Custom attributes on 'normal' elements</title>
|
||||
<para>Writing your own custom parser and the associated artifacts isn't hard, but sometimes it
|
||||
is not the right thing to do. Consider the scenario where you need to add metadata to already
|
||||
existing bean definitions. In this case you certainly don't want to have to go off and write
|
||||
your own entire custom extension; rather you just want to add an additional attribute
|
||||
to the existing bean definition element.</para>
|
||||
<para>By way of another example, let's say that the service class that you are defining a bean
|
||||
definition for a service object that will (unknown to it) be accessing a clustered
|
||||
<ulink url="http://jcp.org/en/jsr/detail?id=107">JCache</ulink>, and you want to ensure that
|
||||
the named JCache instance is eagerly started within the surrounding cluster:</para>
|
||||
<programlisting><![CDATA[<bean id="checkingAccountService" class="com.foo.DefaultCheckingAccountService"
|
||||
]]><lineannotation><emphasis role="bold">jcache:cache-name="checking.account"></emphasis></lineannotation><![CDATA[
|
||||
]]><lineannotation><!-- other dependencies here... --></lineannotation><![CDATA[
|
||||
</bean>]]></programlisting>
|
||||
<para>What we are going to do here is create another <interfacename>BeanDefinition</interfacename>
|
||||
when the <literal>'jcache:cache-name'</literal> attribute is parsed; this
|
||||
<interfacename>BeanDefinition</interfacename> will then initialize the named JCache
|
||||
for us. We will also modify the existing <interfacename>BeanDefinition</interfacename> for the
|
||||
<literal>'checkingAccountService'</literal> so that it will have a dependency on this
|
||||
new JCache-initializing <interfacename>BeanDefinition</interfacename>.</para>
|
||||
<programlisting><![CDATA[package com.foo;
|
||||
|
||||
public class JCacheInitializer {
|
||||
|
||||
private String name;
|
||||
|
||||
public JCacheInitializer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
]]><lineannotation>// lots of JCache API calls to initialize the named cache...</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Now onto the custom extension. Firstly, the authoring of the XSD schema describing the
|
||||
custom attribute (quite easy in this case).</para>
|
||||
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
|
||||
<xsd:schema xmlns="http://www.foo.com/schema/jcache"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.foo.com/schema/jcache"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<xsd:attribute name="cache-name" type="xsd:string"/>
|
||||
|
||||
</xsd:schema>
|
||||
]]></programlisting>
|
||||
<para>Next, the associated <interfacename>NamespaceHandler</interfacename>.</para>
|
||||
<programlisting><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
public class JCacheNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
super.registerBeanDefinitionDecoratorForAttribute("cache-name",
|
||||
new JCacheInitializingBeanDefinitionDecorator());
|
||||
}
|
||||
}
|
||||
]]></programlisting>
|
||||
<para>Next, the parser. Note that in this case, because we are going to be parsing an XML
|
||||
attribute, we write a <interfacename>BeanDefinitionDecorator</interfacename> rather than a
|
||||
<interfacename>BeanDefinitionParser</interfacename>.</para>
|
||||
<programlisting><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class JCacheInitializingBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
|
||||
public BeanDefinitionHolder decorate(
|
||||
Node source, BeanDefinitionHolder holder, ParserContext ctx) {
|
||||
String initializerBeanName = registerJCacheInitializer(source, ctx);
|
||||
createDependencyOnJCacheInitializer(holder, initializerBeanName);
|
||||
return holder;
|
||||
}
|
||||
|
||||
private void createDependencyOnJCacheInitializer(BeanDefinitionHolder holder, String initializerBeanName) {
|
||||
AbstractBeanDefinition definition = ((AbstractBeanDefinition) holder.getBeanDefinition());
|
||||
String[] dependsOn = definition.getDependsOn();
|
||||
if (dependsOn == null) {
|
||||
dependsOn = new String[]{initializerBeanName};
|
||||
} else {
|
||||
List dependencies = new ArrayList(Arrays.asList(dependsOn));
|
||||
dependencies.add(initializerBeanName);
|
||||
dependsOn = (String[]) dependencies.toArray(EMPTY_STRING_ARRAY);
|
||||
}
|
||||
definition.setDependsOn(dependsOn);
|
||||
}
|
||||
|
||||
private String registerJCacheInitializer(Node source, ParserContext ctx) {
|
||||
String cacheName = ((Attr) source).getValue();
|
||||
String beanName = cacheName + "-initializer";
|
||||
if (!ctx.getRegistry().containsBeanDefinition(beanName)) {
|
||||
BeanDefinitionBuilder initializer = BeanDefinitionBuilder.rootBeanDefinition(JCacheInitializer.class);
|
||||
initializer.addConstructorArg(cacheName);
|
||||
ctx.getRegistry().registerBeanDefinition(beanName, initializer.getBeanDefinition());
|
||||
}
|
||||
return beanName;
|
||||
}
|
||||
}
|
||||
]]></programlisting>
|
||||
<para>Lastly, the various artifacts need to be registered with the Spring XML infrastructure.</para>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.handlers'</filename></lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler]]></programlisting>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.schemas'</filename></lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/jcache/jcache.xsd=com/foo/jcache.xsd]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
<section id="extensible-xml-resources">
|
||||
<title>Further Resources</title>
|
||||
<para>Find below links to further resources concerning XML Schema and the extensible XML support
|
||||
described in this chapter.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/">XML Schema Part 1: Structures Second Edition</ulink></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/">XML Schema Part 2: Datatypes Second Edition</ulink></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</appendix>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version='1.0'>
|
||||
|
||||
<!-- Extensions -->
|
||||
<xsl:param name="use.extensions">1</xsl:param>
|
||||
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||
<xsl:param name="callout.extensions">1</xsl:param>
|
||||
|
||||
<!-- Activate Graphics -->
|
||||
<xsl:param name="admon.graphics" select="1"/>
|
||||
<xsl:param name="admon.graphics.path">images/</xsl:param>
|
||||
<xsl:param name="admon.graphics.extension">.gif</xsl:param>
|
||||
<xsl:param name="callout.graphics" select="1" />
|
||||
<xsl:param name="callout.defaultcolumn">120</xsl:param>
|
||||
<xsl:param name="callout.graphics.path">images/callouts/</xsl:param>
|
||||
<xsl:param name="callout.graphics.extension">.gif</xsl:param>
|
||||
|
||||
<xsl:param name="table.borders.with.css" select="1"/>
|
||||
<xsl:param name="html.stylesheet">css/stylesheet.css</xsl:param>
|
||||
<xsl:param name="html.stylesheet.type">text/css</xsl:param>
|
||||
<xsl:param name="generate.toc">book toc,title</xsl:param>
|
||||
|
||||
<xsl:param name="admonition.title.properties">text-align: left</xsl:param>
|
||||
|
||||
<!-- Label Chapters and Sections (numbering) -->
|
||||
<xsl:param name="chapter.autolabel" select="1"/>
|
||||
<xsl:param name="section.autolabel" select="1"/>
|
||||
<xsl:param name="section.autolabel.max.depth" select="1"/>
|
||||
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||
<xsl:param name="table.footnote.number.format" select="'1'"/>
|
||||
|
||||
<!-- Remove "Chapter" from the Chapter titles... -->
|
||||
<xsl:param name="local.l10n.xml" select="document('')"/>
|
||||
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
|
||||
<l:l10n language="en">
|
||||
<l:context name="title-numbered">
|
||||
<l:template name="chapter" text="%n. %t"/>
|
||||
<l:template name="section" text="%n %t"/>
|
||||
</l:context>
|
||||
</l:l10n>
|
||||
</l:i18n>
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0"
|
||||
xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
|
||||
<!-- ==================================================================== -->
|
||||
|
||||
<t:titlepage t:element="book" t:wrapper="div" class="titlepage">
|
||||
<t:titlepage-content t:side="recto">
|
||||
<productname/>
|
||||
<title/>
|
||||
<subtitle/>
|
||||
<!-- <corpauthor/>
|
||||
<authorgroup/>
|
||||
<author/>
|
||||
<mediaobject/> -->
|
||||
<othercredit/>
|
||||
<releaseinfo/>
|
||||
<copyright/>
|
||||
<legalnotice/>
|
||||
<pubdate/>
|
||||
<revision/>
|
||||
<revhistory/>
|
||||
<abstract/>
|
||||
</t:titlepage-content>
|
||||
|
||||
<t:titlepage-content t:side="verso">
|
||||
</t:titlepage-content>
|
||||
|
||||
<t:titlepage-separator>
|
||||
<hr/>
|
||||
</t:titlepage-separator>
|
||||
|
||||
<t:titlepage-before t:side="recto">
|
||||
</t:titlepage-before>
|
||||
|
||||
<t:titlepage-before t:side="verso">
|
||||
</t:titlepage-before>
|
||||
</t:titlepage>
|
||||
|
||||
</t:templates>
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
version='1.0'>
|
||||
|
||||
<!-- Use nice graphics for admonitions -->
|
||||
<xsl:param name="admon.graphics">'1'</xsl:param>
|
||||
<xsl:param name="admon.graphics.path">@file.prefix@@dbf.xsl@/images/</xsl:param>
|
||||
<xsl:param name="draft.watermark.image" select="'@file.prefix@@dbf.xsl@/images/draft.png'"/>
|
||||
<xsl:param name="paper.type" select="'@paper.type@'"/>
|
||||
|
||||
<xsl:param name="page.margin.top" select="'1cm'"/>
|
||||
<xsl:param name="region.before.extent" select="'1cm'"/>
|
||||
<xsl:param name="body.margin.top" select="'1.5cm'"/>
|
||||
|
||||
<xsl:param name="body.margin.bottom" select="'1.5cm'"/>
|
||||
<xsl:param name="region.after.extent" select="'1cm'"/>
|
||||
<xsl:param name="page.margin.bottom" select="'1cm'"/>
|
||||
<xsl:param name="title.margin.left" select="'0cm'"/>
|
||||
|
||||
<!--###################################################
|
||||
Header
|
||||
################################################### -->
|
||||
|
||||
<!-- More space in the center header for long text -->
|
||||
<xsl:attribute-set name="header.content.properties">
|
||||
<xsl:attribute name="font-family">
|
||||
<xsl:value-of select="$body.font.family"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">-5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-right">-5em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Table of Contents
|
||||
################################################### -->
|
||||
|
||||
<xsl:param name="generate.toc">
|
||||
book toc,title
|
||||
</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Custom Header
|
||||
################################################### -->
|
||||
|
||||
<xsl:template name="header.content">
|
||||
<xsl:param name="pageclass" select="''"/>
|
||||
<xsl:param name="sequence" select="''"/>
|
||||
<xsl:param name="position" select="''"/>
|
||||
<xsl:param name="gentext-key" select="''"/>
|
||||
|
||||
<xsl:variable name="Version">
|
||||
<xsl:choose>
|
||||
<xsl:when test="//productname">
|
||||
<xsl:value-of select="//productname"/><xsl:text> </xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>please define productname in your docbook file!</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="$sequence='blank'">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$position='center'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$pageclass='titlepage'">
|
||||
<!-- nop: other titlepage sequences have no header -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$position='center'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Custom Footer
|
||||
################################################### -->
|
||||
|
||||
<xsl:template name="footer.content">
|
||||
<xsl:param name="pageclass" select="''"/>
|
||||
<xsl:param name="sequence" select="''"/>
|
||||
<xsl:param name="position" select="''"/>
|
||||
<xsl:param name="gentext-key" select="''"/>
|
||||
|
||||
<xsl:variable name="Version">
|
||||
<xsl:choose>
|
||||
<xsl:when test="//releaseinfo">
|
||||
<xsl:value-of select="//releaseinfo"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:variable name="Title">
|
||||
<xsl:value-of select="//title"/>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="$sequence='blank'">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$double.sided != 0 and $position = 'left'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position = 'center'">
|
||||
<!-- nop -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<fo:page-number/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$pageclass='titlepage'">
|
||||
<!-- nop: other titlepage sequences have no footer -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='right'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='left'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$position='center'">
|
||||
<xsl:value-of select="$Title"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="processing-instruction('hard-pagebreak')">
|
||||
<fo:block break-before='page'/>
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Extensions
|
||||
################################################### -->
|
||||
|
||||
<!-- These extensions are required for table printing and other stuff -->
|
||||
<xsl:param name="use.extensions">1</xsl:param>
|
||||
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||
<xsl:param name="callout.extensions">1</xsl:param>
|
||||
<xsl:param name="fop.extensions">1</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Paper & Page Size
|
||||
################################################### -->
|
||||
|
||||
<!-- Paper type, no headers on blank pages, no double sided printing -->
|
||||
<xsl:param name="double.sided">0</xsl:param>
|
||||
<xsl:param name="headers.on.blank.pages">0</xsl:param>
|
||||
<xsl:param name="footers.on.blank.pages">0</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Fonts & Styles
|
||||
################################################### -->
|
||||
|
||||
<xsl:param name="hyphenate">false</xsl:param>
|
||||
|
||||
<!-- Default Font size -->
|
||||
<xsl:param name="body.font.master">11</xsl:param>
|
||||
<xsl:param name="body.font.small">8</xsl:param>
|
||||
|
||||
<!-- Line height in body text -->
|
||||
<xsl:param name="line-height">1.4</xsl:param>
|
||||
|
||||
<!-- Chapter title size -->
|
||||
<xsl:attribute-set name="chapter.titlepage.recto.style">
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.8"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Why is the font-size for chapters hardcoded in the XSL FO templates?
|
||||
Let's remove it, so this sucker can use our attribute-set only... -->
|
||||
<xsl:template match="title" mode="chapter.titlepage.recto.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
xsl:use-attribute-sets="chapter.titlepage.recto.style">
|
||||
<xsl:call-template name="component.title">
|
||||
<xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/>
|
||||
</xsl:call-template>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Sections 1, 2 and 3 titles have a small bump factor and padding -->
|
||||
<xsl:attribute-set name="section.title.level1.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.5"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="section.title.level2.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.25"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="section.title.level3.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.0"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Tables
|
||||
################################################### -->
|
||||
|
||||
<!-- Some padding inside tables -->
|
||||
<xsl:attribute-set name="table.cell.padding">
|
||||
<xsl:attribute name="padding-left">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">4pt</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Only hairlines as frame and cell borders in tables -->
|
||||
<xsl:param name="table.frame.border.thickness">0.1pt</xsl:param>
|
||||
<xsl:param name="table.cell.border.thickness">0.1pt</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Labels
|
||||
################################################### -->
|
||||
|
||||
<!-- Label Chapters and Sections (numbering) -->
|
||||
<xsl:param name="chapter.autolabel" select="1"/>
|
||||
<xsl:param name="section.autolabel" select="1"/>
|
||||
<xsl:param name="section.autolabel.max.depth" select="1"/>
|
||||
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||
<xsl:param name="table.footnote.number.format" select="'1'"/>
|
||||
|
||||
<!--###################################################
|
||||
Programlistings
|
||||
################################################### -->
|
||||
|
||||
<!-- Verbatim text formatting (programlistings) -->
|
||||
<xsl:attribute-set name="monospace.verbatim.properties">
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.small * 1.0"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="verbatim.properties">
|
||||
<xsl:attribute name="space-before.minimum">1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.optimum">1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">1em</xsl:attribute>
|
||||
<!-- alef: commented out because footnotes were screwed because of it -->
|
||||
<!--<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>-->
|
||||
|
||||
<xsl:attribute name="border-color">#444444</xsl:attribute>
|
||||
<xsl:attribute name="border-style">solid</xsl:attribute>
|
||||
<xsl:attribute name="border-width">0.1pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-right">0.5em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Shade (background) programlistings -->
|
||||
<xsl:param name="shade.verbatim">1</xsl:param>
|
||||
<xsl:attribute-set name="shade.verbatim.style">
|
||||
<xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="list.block.spacing">
|
||||
<xsl:attribute name="space-before.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="example.properties">
|
||||
<xsl:attribute name="space-before.minimum">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.optimum">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="keep-together.within-column">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Title information for Figures, Examples etc.
|
||||
################################################### -->
|
||||
|
||||
<xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing">
|
||||
<xsl:attribute name="font-weight">normal</xsl:attribute>
|
||||
<xsl:attribute name="font-style">italic</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="hyphenate">false</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Callouts
|
||||
################################################### -->
|
||||
|
||||
<!-- don't use images for callouts -->
|
||||
<xsl:param name="callout.graphics">0</xsl:param>
|
||||
<xsl:param name="callout.unicode">1</xsl:param>
|
||||
|
||||
<!-- Place callout marks at this column in annotated areas -->
|
||||
<xsl:param name="callout.defaultcolumn">90</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Misc
|
||||
################################################### -->
|
||||
|
||||
<!-- Placement of titles -->
|
||||
<xsl:param name="formal.title.placement">
|
||||
figure after
|
||||
example after
|
||||
equation before
|
||||
table before
|
||||
procedure before
|
||||
</xsl:param>
|
||||
|
||||
<!-- Format Variable Lists as Blocks (prevents horizontal overflow) -->
|
||||
<xsl:param name="variablelist.as.blocks">1</xsl:param>
|
||||
|
||||
<xsl:param name="body.start.indent">0pt</xsl:param>
|
||||
|
||||
<!-- Remove "Chapter" from the Chapter titles... -->
|
||||
<xsl:param name="local.l10n.xml" select="document('')"/>
|
||||
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
|
||||
<l:l10n language="en">
|
||||
<l:context name="title-numbered">
|
||||
<l:template name="chapter" text="%n. %t"/>
|
||||
<l:template name="section" text="%n %t"/>
|
||||
</l:context>
|
||||
<l:context name="title">
|
||||
<l:template name="example" text="Example %n %t"/>
|
||||
</l:context>
|
||||
</l:l10n>
|
||||
</l:i18n>
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
<?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>
|
||||