Update reference documentation generation tools to get source highlighting [SPRNET-1045]

This commit is contained in:
bbaia
2008-10-05 17:25:10 +00:00
parent 26cb75d4e0
commit 5dfa039603
125 changed files with 4487 additions and 7338 deletions

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8" ?>
<project name="DocBook" default="help" xmlns="http://nant.sf.net/release/0.85/nant.xsd">
<property name="project.basedir" value="${project::get-base-directory()}" />
<target name="help">
<echo message="Avalaible tasks :" />
<echo message=" all" />
<echo message=" html" />
<echo message=" html-help" />
<echo message=" pdf" />
</target>
<target name="all" depends="html,html-help,pdf"/>
<target name="html">
<echo message="Generating HTML format..." />
<!-- docbook -> html -->
<exec program="java" commandline='-cp "lib\saxon6-5-5\saxon.jar;lib\xslthl-2.0.0\xslthl-2.0.0.jar" com.icl.saxon.StyleSheet src/index.xml "lib\docbook-xsl-snapshot\html\springnet.xsl" highlight.xslthl.config="file:///${project.basedir}/lib/docbook-xsl-snapshot/highlighting/xslthl-config.xml"' />
<!-- copy css to html dir -->
<copy todir="${project.basedir}\html\styles">
<fileset basedir="${project.basedir}\src\styles">
<include name="**"/>
</fileset>
</copy>
<!-- copy images to html dir -->
<copy todir="${project.basedir}\html\images">
<fileset basedir="${project.basedir}\src\images">
<include name="*.gif"/>
<include name="*.svg"/>
<include name="*.jpg"/>
<include name="*.png"/>
</fileset>
</copy>
<copy todir="${project.basedir}\html\images">
<fileset basedir="${project.basedir}\lib\docbook-xsl-snapshot\images">
<include name="**"/>
</fileset>
</copy>
</target>
<target name="html-help">
<echo message="Generating HTML Help format..." />
<!-- docbook -> HTML Help Workshop project (.hhp) -->
<exec program="java" commandline='-cp "lib\saxon6-5-5\saxon.jar;lib\xslthl-2.0.0\xslthl-2.0.0.jar" com.icl.saxon.StyleSheet src/index.xml "lib\docbook-xsl-snapshot\htmlhelp\springnet.xsl" highlight.xslthl.config="file:///${project.basedir}/lib/docbook-xsl-snapshot/highlighting/xslthl-config.xml"' />
<!-- copy css to html dir -->
<copy todir="${project.basedir}\htmlhelp\styles">
<fileset basedir="${project.basedir}\src\styles">
<include name="**"/>
</fileset>
</copy>
<!-- copy images to htmlhelp dir -->
<copy todir="${project.basedir}\htmlhelp\images">
<fileset basedir="${project.basedir}\src\images">
<include name="*.gif"/>
<include name="*.svg"/>
<include name="*.jpg"/>
<include name="*.png"/>
</fileset>
</copy>
<copy todir="${project.basedir}\htmlhelp\images">
<fileset basedir="${project.basedir}\lib\docbook-xsl-snapshot\images">
<include name="**"/>
</fileset>
</copy>
<!-- HTML Help Workshop project (.hhp) -> HTML Help file (.chm) -->
<!--<readregistry property="hhc.path" key="SOFTWARE\Microsoft\HTML Help Workshop\InstallDir" hive="CurrentUser" />-->
<exec program="C:\Program Files\HTML Help Workshop\hhc.exe" commandline="${project.basedir}\htmlhelp\htmlhelp.hhp" failonerror="false" />
<!-- cleanup -->
<delete>
<fileset basedir="${project.basedir}\htmlhelp" >
<include name="**/**"/>
<exclude name="*.chm"/>
</fileset>
</delete>
</target>
<target name="pdf">
<echo message="Generating PDF format..." />
<!-- docbook -> fop -->
<exec program="java" commandline='-cp "lib\saxon6-5-5\saxon.jar;lib\xslthl-2.0.0\xslthl-2.0.0.jar" com.icl.saxon.StyleSheet -o pdf/spring-net-reference.fo src/index.xml "lib\docbook-xsl-snapshot\fo\springnet.xsl" highlight.xslthl.config="file:///${project.basedir}/lib/docbook-xsl-snapshot/highlighting/xslthl-config.xml"'/>
<!-- fop -> pdf -->
<exec program="${project.basedir}\lib\fop-0.95\fop.bat" commandline='-fo "${project.basedir}\pdf\spring-net-reference.fo" -pdf "${project.basedir}\pdf\spring-net-reference.pdf"'/>
<!-- Delete temporary fop file -->
<delete file="${project.basedir}\pdf\spring-net-reference.fo"/>
</target>
</project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 B

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,10 +16,10 @@
* limitations under the License.
*/
-->
<chapter id="ajax">
<chapter xml:id="ajax" xmlns="http://docbook.org/ns/docbook" version="5">
<title>ASP.NET AJAX</title>
<sect1 id="introduction-ajax">
<sect1 xml:id="introduction-ajax">
<title>Introduction</title>
<para>Spring's ASP.NET AJAX integration allows for a plain .NET object
@@ -29,40 +29,40 @@
JavaScript.</para>
</sect1>
<sect1 id="webServices">
<sect1 xml:id="webServices">
<title>Web Services</title>
<para>Spring.NET, and particularly Spring.Web, improved <ulink
url="http://www.springframework.net/doc-latest/reference/html/webservices.html">support
for web services</ulink> in .NET with the
<classname>WebServiceExporter</classname>. Exporting of an ordinary plain
<literal>WebServiceExporter</literal>. Exporting of an ordinary plain
.NET object as a web service is achieved by registering a custom
implementation of the <classname>WebServiceHandlerFactory</classname>
implementation of the <literal>WebServiceHandlerFactory</literal>
class as the HTTP handler for <literal>*.asmx</literal> requests.</para>
<para><ulink
url="http://www.springframework.net/doc-latest/reference/html/webservices.html">Microsoft
ASP.NET AJAX</ulink> introduced a new HTTP handler
<classname>System.Web.Script.Services.ScriptHandlerFactory</classname> to
<literal>System.Web.Script.Services.ScriptHandlerFactory</literal> to
allow a Web Service to be invoked from the browser by using
JavaScript.</para>
<para>Spring's integration allows for both Spring.Web and ASP.NET AJAX
functionality to be used together by creating a new HTTP handler.</para>
<sect2 id="exposingWebServices">
<sect2 xml:id="exposingWebServices">
<title>Exposing Web Services</title>
<para>The <classname>WebServiceExporter</classname> combined with the
<para>The <literal>WebServiceExporter</literal> combined with the
new HTTP handler exposes PONOs as Web Services in your ASP.NET AJAX
application.</para>
<para>In order for a Web service to be accessed from script, the
<classname>WebServiceExporter</classname> should decorate the Web
Service class with the <classname>ScriptServiceAttribute</classname>.
<literal>WebServiceExporter</literal> should decorate the Web
Service class with the <literal>ScriptServiceAttribute</literal>.
The code below is taken from the sample application
Spring.Web.Extensions.Sample, aka the 'AJAX' shortcut in the
installation. : <programlisting>
installation. : <programlisting language="myxml">
&lt;object id="ContactWebService" type="Spring.Web.Services.WebServiceExporter, Spring.Web"&gt;
&lt;property name="TargetName" value="ContactService"/&gt;
&lt;property name="Namespace" value="http://Spring.Examples.Atlas/ContactService"/&gt;
@@ -77,15 +77,17 @@
</programlisting></para>
<para>All that one needs to do in order to use the
<classname>WebServiceExporter</classname> is:</para>
<literal>WebServiceExporter</literal> is:</para>
<para><emphasis> 1. Configure the Web.config file of your ASP.NET AJAX
application as a Spring.Web application. </emphasis> <programlisting>
application as a Spring.Web application. </emphasis>
<programlisting language="myxml">
&lt;sectionGroup name="spring"&gt;
&lt;section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/&gt;
&lt;/sectionGroup&gt;
</programlisting> <programlisting>
</programlisting>
<programlisting language="myxml">
&lt;spring&gt;
&lt;context&gt;
&lt;resource uri="~/Spring.config"/&gt;
@@ -96,7 +98,7 @@
<para><emphasis> 2. Register the HTTP handler and the Spring HttpModule
under the <literal>system.web</literal> section. </emphasis>
<programlisting>
<programlisting language="myxml">
&lt;httpHandlers&gt;
&lt;remove verb="*" path="*.asmx"/&gt;
&lt;add verb="*" path="*.asmx" validate="false" type="Spring.Web.Script.Services.ScriptHandlerFactory, Spring.Web.Extensions"/&gt;
@@ -113,7 +115,7 @@
<para><emphasis> 3. Register the HTTP handler and the Spring HttpModule
under <literal>system.webServer</literal> section. </emphasis>
<programlisting>
<programlisting language="myxml">
&lt;modules&gt;
&lt;add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/&gt;
&lt;add name="SpringModule" type="Spring.Context.Support.WebSupportModule, Spring.Web"/&gt;
@@ -133,14 +135,14 @@
this integration.</para>
</sect2>
<sect2 id="callingWebServices">
<sect2 xml:id="callingWebServices">
<title>Calling Web Services by using JavaScript</title>
<para>A proxy class is generated for each Web Service. Calls to Web
Services methods are made by using this proxy class. When using the
<classname>WebServiceExporter</classname>, the name of the proxy class
is equal to the <classname>WebServiceExporter</classname>'s id.
<programlisting>
<literal>WebServiceExporter</literal>, the name of the proxy class
is equal to the <literal>WebServiceExporter</literal>'s id.
<programlisting language="csharp">
// This function calls the Contact Web service method
// passing simple type parameters and the callback function
function GetEmails(prefix, count)

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="aop-aspect-library">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="aop-aspect-library" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Aspect Library</title>
<sect1 id="aop-library-introduction">
<sect1 xml:id="aop-library-introduction">
<title>Introduction</title>
<para>Spring provides several aspects in the distribution. The most
@@ -15,7 +32,7 @@
release.</para>
</sect1>
<sect1 id="caching-aspect">
<sect1 xml:id="caching-aspect">
<title>Caching</title>
<para>Caching the return value of a method or the value of a method
@@ -34,12 +51,12 @@
functionality and its configuration.</para>
<para>The base cache interface that any cache implementation should
implement is <classname>Spring.Caching.ICache</classname> located in
<classname>Spring.Core.</classname> Two implementations are provided,
<classname>Spring.Caching.AspNetCache </classname>located in
<classname>Spring.Web</classname> which stores cache entries within an
implement is <literal>Spring.Caching.ICache</literal> located in
<literal>Spring.Core</literal>. Two implementations are provided,
<literal>Spring.Caching.AspNetCache</literal> located in
<literal>Spring.Web</literal> which stores cache entries within an
ASP.NET cache and a simple implementation,
<classname>Spring.Caching.NonExpiringCache</classname> that stores cache
<literal>Spring.Caching.NonExpiringCache</literal> that stores cache
entries in memory and never expires these entries. Custom implementations
based on 3rd party implementations, such as Oracle Coherence, or
memcached, can be used by implementing the <literal>ICache</literal>
@@ -59,18 +76,18 @@
<itemizedlist>
<listitem>
<para><literal>CacheResult - used to cache the return
value</literal></para>
<para><literal>CacheResult</literal> - used to cache the return
value</para>
</listitem>
<listitem>
<para><literal>CacheResultItems - used when returning a collection as
a return value </literal></para>
<para><literal>CacheResultItems</literal> - used when returning a collection as
a return value</para>
</listitem>
<listitem>
<para><literal>CacheParameter - used to cache a method
parameter</literal></para>
<para><literal>CacheParameter</literal> - used to cache a method
parameter</para>
</listitem>
<listitem>
@@ -79,9 +96,9 @@
</listitem>
</itemizedlist>
<para>Each <classname>CacheResult</classname>,
<classname>CacheResultItems</classname>, and
<classname>CacheParameter</classname> attributes define the following
<para>Each <literal>CacheResult</literal>,
<literal>CacheResultItems</literal>, and
<literal>CacheParameter</literal> attributes define the following
properties.</para>
<itemizedlist>
@@ -108,13 +125,13 @@
</listitem>
</itemizedlist>
<para>The <classname>InvalidateCache</classname> attribute has properties
<para>The <literal>InvalidateCache</literal> attribute has properties
for the CacheName, the Key as well as the Condition, with the same
meanings as listed previously.</para>
<para>Each <classname>ICache</classname> implementation will have
<para>Each <literal>ICache</literal> implementation will have
properties that are specific to a caching technology. In the case of
<classname>AspNetCache</classname>, the two important properties to
<literal>AspNetCache</literal>, the two important properties to
configure are:</para>
<itemizedlist>
@@ -166,12 +183,11 @@
sample application of the AirportDao implementation that implements an
interface with the method GetAirport(long id).</para>
<programlisting> [CacheResult("AspNetCache", "'Airport.Id=' + #id", TimeToLive = "0:1:0")]
public Airport GetAirport(long id)
{
// implementation not shown...
}
</programlisting>
<programlisting language="csharp">[<classname>CacheResult</classname>("AspNetCache", "'Airport.Id=' + #id", TimeToLive = "0:1:0")]
public <classname>Airport</classname> GetAirport(long id)
{
// implementation not shown...
}</programlisting>
<para>The first parameter is the cache name. The second string parameter
is the cache key and is a string expression that incorporates the argument
@@ -186,35 +202,35 @@
<para>The configuration to enable the caching aspect is shown below</para>
<programlisting> &lt;object id="CacheAspect" type="Spring.Aspects.Cache.CacheAspect, Spring.Aop"/&gt;
&lt;object id="AspNetCache" type="Spring.Caching.AspNetCache, Spring.Web"&gt;
&lt;property name="SlidingExpiration" value="true"/&gt;
&lt;property name="Priority" value="Low"/&gt;
&lt;property name="TimeToLive" value="00:02:00"/&gt;
&lt;/object&gt;
<programlisting language="myxml"><![CDATA[<object" id="CacheAspect" type="Spring.Aspects.Cache.CacheAspect, Spring.Aop"/>
<object id="AspNetCache" type="Spring.Caching.AspNetCache, Spring.Web">
<property name="SlidingExpiration" value="true"/>
<property name="Priority" value="Low"/>
<property name="TimeToLive" value="00:02:00"/>
</object>
&lt;!-- Apply aspects to DAOs --&gt;
&lt;object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop"&gt;
&lt;property name="ObjectNames"&gt;
&lt;list&gt;
&lt;value&gt;*Dao&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="InterceptorNames"&gt;
&lt;list&gt;
&lt;value&gt;CacheAspect&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/object&gt;</programlisting>
<!-- Apply aspects to DAOs -->
<object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
<property name="ObjectNames">
<list>
<value>*Dao</value>
</list>
</property>
<property name="InterceptorNames">
<list>
<value>CacheAspect</value>
</list>
</property>
</object>]]></programlisting>
<para>in this example an <classname>ObjectNameAutoProxyCreator</classname>
<para>in this example an <literal>ObjectNameAutoProxyCreator</literal>
was used to apply the cache aspect to objects that have Dao in their name.
The AspNetCache setting for TimeToLive will override the TimeToLive value
set at the method level via the attribute.</para>
</sect1>
<sect1 id="exception-aspect">
<sect1 xml:id="exception-aspect">
<title>Exception Handling</title>
<para>In some cases existing code can be easily adopted to a simple error
@@ -252,13 +268,13 @@
could be referred to as a Domain Specific Language (DSL). Here is a simple
example, which should hopefully be self explanatory.</para>
<para><programlisting>&lt;object name="exceptionHandlingAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop"&gt;
&lt;property name="exceptionHandlers"&gt;
&lt;list&gt;
&lt;value&gt;<emphasis role="bold">on exception name ArithmeticException wrap System.InvalidOperationException</emphasis>&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/object&gt;</programlisting>What this is instructing the advice to do is
<para><programlisting language="myxml"><![CDATA[<object name="exceptionHandlingAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
<property name="exceptionHandlers">
<list>
<value>on exception name ArithmeticException wrap System.InvalidOperationException</value>
</list>
</property>
</object>]]></programlisting>What this is instructing the advice to do is
the following bit of code when an ArithmeticException is thrown, throw new
System.InvalidOperationException("Wrapped ArithmeticException", e), where
e is the original ArithmeticException. The default message, "Wrapped
@@ -283,7 +299,7 @@ on exception name ArithmeticException replace System.InvalidOperationException '
<para><programlisting>on exception name ArithmeticException translate new System.InvalidOperationException('My Message, Method Name ' + #method.Name, #e)</programlisting>What
we see here after the translate keyword is text that will be passed into
Spring's expression language (SpEL) for evaluation. Refer to the chapter
on the <link linkend="expression">expression language</link> for more
on the <link linkend="expressions">expression language</link> for more
details. One important feature of the expression evaluation is the
availability of variables relating to the calling context when the
exception was thrown. These are</para>
@@ -340,7 +356,7 @@ on exception name ArithmeticException return 12</programlisting>
action, i.e. log(Debug,"LoggerName").</para>
<para>Multiple exception handling statements can be specified within the
&lt;list&gt; shown above. The processing flow is on exception, the name of
list shown above. The processing flow is on exception, the name of
the exception listed in the statement is compared to the thrown exception
to see if there is a match. A comma separated list of exceptions can be
used to group together the same action taken for different exception
@@ -383,17 +399,17 @@ on exception name ArithmeticException return 12</programlisting>
for example setting the logging level and pass the exception into the
logging subsystem</para>
<programlisting>&lt;object name="exceptionHandlingAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop"&gt;
&lt;property name="exceptionHandlers"&gt;
&lt;list&gt;
&lt;object type="Spring.Aspects.Exceptions.LogExceptionHandler"&gt;
&lt;property name="LogName" value="Cms.Session.ExceptionHandler" /&gt;
&lt;property name="ConstraintExpressionText" value="#e is T(System.Threading.ThreadAbortException)" /&gt;
&lt;property name="ActionExpressionText" value="#log.Fatal('Request Timeout occured', #e)" /&gt;
&lt;/object&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/object&gt;</programlisting>
<programlisting language="myxml"><![CDATA[<object name="exceptionHandlingAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
<property name="exceptionHandlers">
<list>
<object type="Spring.Aspects.Exceptions.LogExceptionHandler">
<property name="LogName" value="Cms.Session.ExceptionHandler" />
<property name="ConstraintExpressionText" value="#e is T(System.Threading.ThreadAbortException)" />
<property name="ActionExpressionText" value="#log.Fatal('Request Timeout occured', #e)" />
</object>
</list>
</property>
</object>]]></programlisting>
<para>The configuration of the logger name, level, and weather or not to
pass the thrown exception as the second argument to the log method will be
@@ -455,12 +471,12 @@ on exception name ArithmeticException return 12</programlisting>
</sect2>
</sect1>
<sect1 id="logging-aspect">
<sect1 xml:id="logging-aspect">
<title>Logging</title>
<para>The logging advice lets you log the information on method entry,
exit and thrown exception (if any). The implementation is based on the
logging library, <link linkend="???">Common.Logging</link>, that provides
logging library, <ulink url="http://netcommon.sourceforge.net/">Common.Logging</ulink>, that provides
portability across different logging libraries. There are a number of
configuration options available, listed below</para>
@@ -492,21 +508,21 @@ on exception name ArithmeticException return 12</programlisting>
<para>You declare the logging advice in IoC container with the following
XML fragment. Alternatively, you can use the class
<classname>SimpleLoggingAdvice</classname> programatically.</para>
<literal>SimpleLoggingAdvice</literal> programatically.</para>
<programlisting>&lt;object name="loggingAdvice" type="Spring.Aspects.Logging.SimpleLoggingAdvice, Spring.Aop"&gt;
&lt;property name="logUniqueIdentifier" value="true"/&gt;
&lt;property name="logExecutionTime" value="true"/&gt;
&lt;property name="logMethodArguments" value="true"/&gt;
&lt;property name="LogReturnValue" value="true"/&gt;
<programlisting language="myxml"><![CDATA[<object name="loggingAdvice" type="Spring.Aspects.Logging.SimpleLoggingAdvice, Spring.Aop">
<property name="logUniqueIdentifier" value="true"/>
<property name="logExecutionTime" value="true"/>
<property name="logMethodArguments" value="true"/>
<property name="LogReturnValue" value="true"/>
&lt;property name="Separator" value=";"/&gt;
&lt;property name="LogLevel" value="Info"/&gt;
<property name="Separator" value=";"/>
<property name="LogLevel" value="Info"/>
&lt;property name="HideProxyTypeNames" value="true"/&gt;
&lt;property name="UseDynamicLogger" value="true"/&gt;
&lt;/object&gt;</programlisting>
<property name="HideProxyTypeNames" value="true"/>
<property name="UseDynamicLogger" value="true"/>
</object>]]></programlisting>
<para>The default values for LogUniqueIdentifier, LogExecutionTime,
LogMethodArguments and LogReturnValue are false. The default separator
@@ -526,8 +542,8 @@ on exception name ArithmeticException return 12</programlisting>
true target type and not the proxy type.</para>
<para>To further extend the functionality of the
<classname>SimpleLoggingAdvice</classname> you can subclass
<classname>SimpleLoggingAdvice</classname> and override the methods</para>
<literal>SimpleLoggingAdvice</literal> you can subclass
<literal>SimpleLoggingAdvice</literal> and override the methods</para>
<itemizedlist>
<listitem>
@@ -551,19 +567,19 @@ on exception name ArithmeticException return 12</programlisting>
<para>The default implementation to calculate a unique identifier is to
use a GUID. You can alter this behavior by overriding the method
<literal>string CreateUniqueIdentifier()</literal>. The
<classname>SimpleLoggingAdvice</classname> class inherits from
<classname>AbstractLoggingAdvice</classname>, which has the abstract
<literal>SimpleLoggingAdvice</literal> class inherits from
<literal>AbstractLoggingAdvice</literal>, which has the abstract
method <literal>object InvokeUnderLog(IMethodInvocation invocation, ILog
log)</literal> and you can also override the method <literal>ILog
GetLoggerForInvocation(IMethodInvocation invocation)</literal> to
customize the logger instance used for logging. Refer to the SDK
documentation for more details on subclassing
<classname>AbstractLoggingAdvice</classname>.</para>
<literal>AbstractLoggingAdvice</literal>.</para>
<para>As an example of the Logging advice's output, adding the advice to
the method</para>
<programlisting>public int Bark(string message, int[] luckyNumbers)
<programlisting language="csharp">public int Bark(string message, int[] luckyNumbers)
{
return 4;
}</programlisting>
@@ -586,7 +602,7 @@ Exiting Bark, 5d2bad47-62cd-435b-8de7-91f12b7f433e, 30453.125 ms, return=4</prog
using similar syntax to the retry and exception handling advice.</para>
</sect1>
<sect1 id="retry-aspect">
<sect1 xml:id="retry-aspect">
<title>Retry</title>
<para>When making a distributed call it is often a common requirement to
@@ -657,11 +673,11 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)</p
</listitem>
</itemizedlist>You declare the advice in IoC container with the
following XML fragment. Alternatively, you can use the
<classname>RetryAdvice</classname> class programatically.</para>
<literal>RetryAdvice</literal> class programatically.</para>
<programlisting>&lt;object name="exceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop"&gt;
&lt;property name="retryExpression" value="<emphasis role="bold">on exception name ArithmeticException retry 3x delay 1s</emphasis>"/&gt;
&lt;/object&gt;</programlisting>
<programlisting language="myxml"><![CDATA[<object name="exceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop">
<property name="retryExpression" value="on exception name ArithmeticException retry 3x delay 1s"/>
</object>]]></programlisting>
<sect2>
<title>Language Reference</title>
@@ -679,14 +695,14 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)</p
</sect2>
</sect1>
<sect1 id="tx-aspect">
<sect1 xml:id="tx-aspect">
<title>Transactions</title>
<para>The transaction aspect is more fully described in the section on
<link linkend="transaction">transaction management</link>.</para>
</sect1>
<sect1 id="parameter-validation">
<sect1 xml:id="parameter-validation">
<title>Parameter Validation</title>
<para>Spring provides a UI-agnostic <link linkend="validation">validation
@@ -705,15 +721,15 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)</p
<para>To address some of the common needs for validation on the server
side, Spring provides parameter validation advice so that applies Spring's
validation rules to the method parameters. The class
<classname>ParameterValidationAdvice</classname> is used in conjunction
with the <classname>Validated</classname> attribute to specify which
<literal>ParameterValidationAdvice</literal> is used in conjunction
with the <literal>Validated</literal> attribute to specify which
validation rules are applied to method parameters. For example, to apply
parameter validation to the method SuggestFlights in the BookingAgent
class used in the <link linkend="springair">SpringAir sample
application</link>, you would apply the <classname>Validated</classname>
application</link>, you would apply the <literal>Validated</literal>
attribute to the method parameters as shown below.</para>
<programlisting>public FlightSuggestions SuggestFlights( [Validated("tripValidator")] Trip trip)
<programlisting language="csharp">public <classname>FlightSuggestions</classname> SuggestFlights( [<classname>Validated</classname>("tripValidator")] <classname>Trip</classname> trip)
{
// unmodified implementation goes here
}</programlisting>
@@ -721,34 +737,34 @@ on exception (#e is T(System.ArithmeticException)) retry 3x rate (1*#n + 0.5)</p
<para>The <literal>Validated</literal> attribute takes a string name that
specifies the name of the validation rule, i.e. the name of the IValidator
object in the Spring application context. The
<classname>Validated</classname> attribute is located in the namespace
<literal>Validated</literal> attribute is located in the namespace
<literal>Spring.Validation</literal> of the <literal>Spring.Core</literal>
assembly.</para>
<para>The configuration of the advice is to simply define the an instance
of the <literal>ParameterValidationAdvice</literal> class and apply the
advice, for example based on object names using an
<classname>ObjectNameAutoProxyCreator</classname>, as shown below,</para>
<literal>ObjectNameAutoProxyCreator</literal>, as shown below,</para>
<programlisting> &lt;object id="<emphasis role="bold">validationAdvice</emphasis>" type="Spring.Aspects.Validation.ParameterValidationAdvice, Spring.Aop"/&gt;
<programlisting language="myxml"><![CDATA[<object id="validationAdvice" type="Spring.Aspects.Validation.ParameterValidationAdvice, Spring.Aop"/>
&lt;object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop"&gt;
&lt;property name="ObjectNames"&gt;
&lt;list&gt;
&lt;value&gt;bookingAgent&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="InterceptorNames"&gt;
&lt;list&gt;
&lt;value&gt;<emphasis role="bold">validationAdvice</emphasis>&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/object&gt;</programlisting>
<object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
<property name="ObjectNames">
<list>
<value>bookingAgent</value>
</list>
</property>
<property name="InterceptorNames">
<list>
<value>validationAdvice</value>
</list>
</property>
</object>]]></programlisting>
<para>When the advised method is invoked first the validation of each
method parameter is performed. If all validation succeeds, then the method
body is executed. If validation fails an exception of the type
<classname>ValidationException</classname> is thrown and you can retrieve
<literal>ValidationException</literal> is thrown and you can retrieve
errors information from its property <literal>ValidationErrors</literal>.
See the SDK documentation for details.</para>
</sect1>

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="aop-quickstart">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="aop-quickstart" xmlns="http://docbook.org/ns/docbook" version="5">
<title>AOP Guide</title>
<sect1 id="aop-quickstart-introduction">
<sect1 xml:id="aop-quickstart-introduction">
<title>Introduction</title>
<para>This is an introductory guide to Aspect Oriented Programming (AOP)
@@ -37,13 +54,13 @@
linkend="springair" />). </emphasis></para>
</sect1>
<sect1 id="aop-quickstart-basics">
<sect1 xml:id="aop-quickstart-basics">
<title>The basics</title>
<para>This initial section introduces the basics of defining and then
applying some simple advice.</para>
<sect2 id="aop-quickstart-basics-advice">
<sect2 xml:id="aop-quickstart-basics-advice">
<title>Applying advice</title>
<para>Lets see (a very basic) example of using Spring.NET AOP. The
@@ -59,27 +76,27 @@
terminology, an instance of the following class is going to be the
<emphasis>advised object</emphasis>.</para>
<programlisting> public interface ICommand
<programlisting language="csharp">public interface ICommand
{
object Execute(object context);
}
public class ServiceCommand : ICommand
{
public object Execute(object context)
{
object Execute(object context);
Console.Out.WriteLine("Service implementation : [{0}]", context);
return null;
}
public class ServiceCommand : ICommand
{
public object Execute(object context)
{
Console.Out.WriteLine("Service implementation : [{0}]", context);
return null;
}
}</programlisting>
}</programlisting>
<para>Find below the advice that is going to be applied to the
<literal>object Execute(object context)</literal> method of the
<classname>ServiceCommand</classname> class. As you can see, this is an
<literal>ServiceCommand</literal> class. As you can see, this is an
example of <emphasis>around advice</emphasis> (see <xref
linkend="aop-introduction-advice-types" />).</para>
<programlisting> public class ConsoleLoggingAroundAdvice : IMethodInterceptor
<programlisting language="csharp"> public class ConsoleLoggingAroundAdvice : IMethodInterceptor
{
public object Invoke(IMethodInvocation invocation)
{
@@ -129,16 +146,16 @@
</calloutlist>
<para>So thus far we have three artifacts: an interface
(<classname>ICommand</classname>); an implementation of said interface
(<classname>ServiceCommand</classname>); and some (trivial) advice
(encapsulated by the <classname>ConsoleLoggingAroundAdvice</classname>
(<literal>ICommand</literal>); an implementation of said interface
(<literal>ServiceCommand</literal>); and some (trivial) advice
(encapsulated by the <literal>ConsoleLoggingAroundAdvice</literal>
class). All that remains is to actually apply the
<classname>ConsoleLoggingAroundAdvice</classname> advice to the
<literal>ConsoleLoggingAroundAdvice</literal> advice to the
invocation of the <literal>Execute()</literal> method of the
<classname>ServiceCommand</classname> class. Lets look at how to effect
<literal>ServiceCommand</literal> class. Lets look at how to effect
this programmatically...</para>
<programlisting> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingAroundAdvice());
ICommand command = (ICommand) factory.GetProxy();
command.Execute("This is the argument");</programlisting>
@@ -152,23 +169,23 @@
<para>The output shows that the advice (the
<literal>Console.Out</literal> statements from the
<classname>ConsoleLoggingAroundAdvice</classname> was applied
<literal>ConsoleLoggingAroundAdvice</literal> was applied
<emphasis>around</emphasis> the invocation of the advised method.</para>
<para>So what is happening here? The fact that the preceding code used a
class called <classname>ProxyFactory</classname> may have clued you in.
The constructor for the <classname>ProxyFactory</classname> class took
class called <literal>ProxyFactory</literal> may have clued you in.
The constructor for the <literal>ProxyFactory</literal> class took
as an argument the object that we wanted to advise (in this case, an
instance of the <classname>ServiceCommand</classname> class). We then
added some advice (a <classname>ConsoleLoggingAroundAdvice</classname>
instance of the <literal>ServiceCommand</literal> class). We then
added some advice (a <literal>ConsoleLoggingAroundAdvice</literal>
instance) using the <literal>AddAdvice()</literal> method of the
<classname>ProxyFactory</classname> instance. We then called the
<literal>ProxyFactory</literal> instance. We then called the
<literal>GetProxy()</literal> method of the
<classname>ProxyFactory</classname> instance which gave us a proxy... an
<literal>ProxyFactory</literal> instance which gave us a proxy... an
(AOP) proxy that proxied the target object (the
<classname>ServiceCommand</classname> instance), and called the advice
<literal>ServiceCommand</literal> instance), and called the advice
(a single instance of the
<classname>ConsoleLoggingAroundAdvice</classname> in this case). When we
<literal>ConsoleLoggingAroundAdvice</literal> in this case). When we
invoked the <literal>Execute(object context)</literal> method of the
proxy, the advice was <literal>'applied'</literal> (executed), as can be
seen from the attendant output.</para>
@@ -184,9 +201,9 @@
<para>One thing to note here is that the AOP proxy that was returned
from the call to the <literal>GetProxy()</literal> method of the
<classname>ProxyFactory</classname> instance was cast to the
<classname>ICommand</classname> interface that the
<classname>ServiceCommand</classname> target object implemented. This is
<literal>ProxyFactory</literal> instance was cast to the
<literal>ICommand</literal> interface that the
<literal>ServiceCommand</literal> target object implemented. This is
very important... currently, Spring.NET's AOP implementation mandates
the use of an interface for advised objects. In short, this means that
in order for your classes to leverage Spring.NET's AOP support, those
@@ -208,7 +225,7 @@
should also be added that this declarative style approach to Spring.NET
AOP is preferred to the programmatic style.</para>
<programlisting> &lt;object id="consoleLoggingAroundAdvice"
<programlisting language="myxml"> &lt;object id="consoleLoggingAroundAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"/&gt;
&lt;object id="myServiceObject" type="Spring.Aop.Framework.ProxyFactoryObject"&gt;
&lt;property name="target"&gt;
@@ -222,50 +239,50 @@
&lt;/property&gt;
&lt;/object&gt;</programlisting>
<programlisting> ICommand command = (ICommand) ctx["myServiceObject"];
<programlisting language="csharp"> ICommand command = (ICommand) ctx["myServiceObject"];
command.Execute();</programlisting>
<para>Some comments are warranted concerning the above XML configuration
snippet. Firstly, note that the
<classname>ConsoleLoggingAroundAdvice</classname> is itself a plain
<literal>ConsoleLoggingAroundAdvice</literal> is itself a plain
vanilla object, and is eligible for configuration just like any other
class... if the advice itself needed to be injected with any
dependencies, any such dependencies could be injected as normal.</para>
<para>Secondly, notice that the object definition corresponding to the
object that is retrieved from the IoC container is a
<classname>ProxyFactoryObject</classname>. The
<classname>ProxyFactoryObject</classname> class is an implementation of
the <classname>IFactoryObject</classname> interface;
<classname>IFactoryObject</classname> implementations are treated
<literal>ProxyFactoryObject</literal>. The
<literal>ProxyFactoryObject</literal> class is an implementation of
the <literal>IFactoryObject</literal> interface;
<literal>IFactoryObject</literal> implementations are treated
specially by the Spring.NET IoC container... in this specific case, it
is not a reference to the <classname>ProxyFactoryObject</classname>
is not a reference to the <literal>ProxyFactoryObject</literal>
instance itself that is returned, but rather the object that the
<classname>ProxyFactoryObject</classname> produces. In this case, it
will be an advised instance of the <classname>ServiceCommand</classname>
<literal>ProxyFactoryObject</literal> produces. In this case, it
will be an advised instance of the <literal>ServiceCommand</literal>
class.</para>
<para>Thirdly, notice that the target of the
<classname>ProxyFactoryObject</classname> is an instance of the
<classname>ServiceCommand</classname> class; this is the object that is
<literal>ProxyFactoryObject</literal> is an instance of the
<literal>ServiceCommand</literal> class; this is the object that is
going to be advised (i.e. invocations of its methods are going to be
intercepted). This object instance is defined as an inner object
definition... this is the preferred idiom for using the
<classname>ProxyFactoryObject</classname>, as it means that other
<literal>ProxyFactoryObject</literal>, as it means that other
objects cannot acquire a reference to the raw object, but rather only
the advised object.</para>
<para>Finally, notice that the advice that is to be applied to the
target object is referred to by its object name in the list of the names
of interceptors for the <classname>ProxyFactoryObject</classname>'s
of interceptors for the <literal>ProxyFactoryObject</literal>'s
<literal>interceptorNames</literal> property. In this particular case,
there is only one instance of advice being applied... the
<classname>ConsoleLoggingAroundAdvice</classname> defined in an object
<literal>ConsoleLoggingAroundAdvice</literal> defined in an object
definition of the same name. The reason for using a list of object names
as opposed to references to the advice objects themselves is explained
in the reference documentation...</para>
<para><emphasis> '... if the <classname>ProxyFactoryObject</classname>'s
<para><emphasis> '... if the <literal>ProxyFactoryObject</literal>'s
singleton property is set to false, it must be able to return
independent proxy instances. If any of the advisors is itself a
prototype, an independent instance would need to be returned, so it is
@@ -273,12 +290,12 @@
context; holding a reference isn't sufficient.' </emphasis></para>
</sect2>
<sect2 id="aop-quickstart-basics-pointcuts">
<sect2 xml:id="aop-quickstart-basics-pointcuts">
<title>Using Pointcuts - the basics</title>
<para>The advice that was applied in the previous section was rather
indiscriminate with regard to which methods on the advised object were
to be advised... the <classname>ConsoleLoggingAroundAdvice</classname>
to be advised... the <literal>ConsoleLoggingAroundAdvice</literal>
simply intercepted <emphasis role="bold">all</emphasis> methods (that
were part of an interface implementation) on the target object.</para>
@@ -292,22 +309,22 @@
<para>The mechanism that Spring.NET AOP uses to discriminate about where
advice is applied (i.e. which method invocations are intercepted) is
encapsulated by the <classname>IPointcut</classname> interface (see
encapsulated by the <literal>IPointcut</literal> interface (see
<xref linkend="aop-pointcuts" />). Spring.NET provides many
out-of-the-box implementations of the <classname>IPointcut</classname>
out-of-the-box implementations of the <literal>IPointcut</literal>
interface... the implementation that is used if none is explicitly
supplied (as was the case with the first example) is the canonical
<classname>TruePointcut</classname> : as the name suggests, this
<literal>TruePointcut</literal> : as the name suggests, this
pointcut always matches, and hence <emphasis role="bold">all</emphasis>
methods that can be advised will be advised.</para>
<para>So let's change the configuration of the advice such that it is
only applied to methods that contain the letters
<literal>'Do'</literal>. We'll change the
<classname>ICommand</classname> interface (and it's attendant
<literal>ICommand</literal> interface (and it's attendant
implementation) to accommodate this...</para>
<programlisting> public interface ICommand
<programlisting language="csharp"> public interface ICommand
{
void Execute();
@@ -328,7 +345,7 @@
}</programlisting>
<para>Please note that the advice itself (encapsulated within the
<classname>ConsoleLoggingAroundAdvice</classname> class) does not need
<literal>ConsoleLoggingAroundAdvice</literal> class) does not need
to change; we are changing <emphasis>where</emphasis> this advice is
applied, and not the advice itself.</para>
@@ -336,7 +353,7 @@
fact that we only want methods that contain the letters
<literal>'Do'</literal> to be advised, looks like this...</para>
<programlisting> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvisor(new DefaultPointcutAdvisor(
new SdkRegularExpressionMethodPointcut("Do"),
new ConsoleLoggingAroundAdvice()));
@@ -346,7 +363,7 @@
<para>The result of executing the above snippet of code will look
something like this...</para>
<programlisting> Intercepted call : about to invoke next item in chain...
<programlisting language="csharp"> Intercepted call : about to invoke next item in chain...
Service implementation...
Intercepted call : returned</programlisting>
@@ -356,7 +373,7 @@
the pertinent code snippet to invoke the <literal>Execute()</literal>
method, like so...</para>
<programlisting> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvisor(
new DefaultPointcutAdvisor(
new SdkRegularExpressionMethodPointcut("Do"),
@@ -376,7 +393,7 @@
<para>XML configuration that accomplishes exactly the same thing as the
previous programmatic configuration example can be seen below...</para>
<programlisting> &lt;object id="consoleLoggingAroundAdvice"
<programlisting language="myxml"> &lt;object id="consoleLoggingAroundAdvice"
type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor"&gt;
&lt;property name="pattern" value="Do"/&gt;
&lt;property name="advice"&gt;
@@ -407,12 +424,12 @@
that match the pattern <literal>'Do'</literal> (the pointcut). The
pattern to match against is supplied as a simple string value to the
<literal>pattern</literal> property of the
<classname>RegularExpressionMethodPointcutAdvisor</classname>
<literal>RegularExpressionMethodPointcutAdvisor</literal>
class.</para>
</sect2>
</sect1>
<sect1 id="aop-quickstart-going-deeper">
<sect1 xml:id="aop-quickstart-going-deeper">
<title>Going deeper</title>
<para>The first section should (hopefully) have demonstrated the basics of
@@ -423,18 +440,18 @@
describes the various advice and pointcuts that are available for you to
use (yes, there is more than one type of advice and pointcut).</para>
<sect2 id="aop-quickstart-going-deeper-other-advice-types">
<sect2 xml:id="aop-quickstart-going-deeper-other-advice-types">
<title>Other types of Advice</title>
<para>The advice that was demonstrated and explained in the preceding
section is what is termed <emphasis>'around advice'</emphasis>. The name
<emphasis>'around advice'</emphasis> is used because the advice is
applied <emphasis>around</emphasis> the target method invocation. In the
specific case of the <classname>ConsoleLoggingAroundAdvice</classname>
specific case of the <literal>ConsoleLoggingAroundAdvice</literal>
advice that was defined previously, the target was made available to the
advice as an <classname>IMethodInvocation</classname> object... a call
was made to the <classname>Console</classname> class before the target
was invoked, and a call was made to the <classname>Console</classname>
advice as an <literal>IMethodInvocation</literal> object... a call
was made to the <literal>Console</literal> class before the target
was invoked, and a call was made to the <literal>Console</literal>
class after the target method invocation was invoked. The advice
surrounded the target, one could even say that the advice was totally
'around' the target... hence the name, <emphasis>'around
@@ -448,14 +465,14 @@
value.</para>
<para>Sometimes you don't need all that power though. If we stick with
the example of the <classname>ConsoleLoggingAroundAdvice</classname>
the example of the <literal>ConsoleLoggingAroundAdvice</literal>
advice, what if one just wants to log the fact that a method was called?
In that case one doesn't need to do anything <emphasis>after</emphasis>
the target method invocation is to be invoked, nor do you need access to
the return value of the target method invocation. In fact, you only want
to do something <emphasis>before</emphasis> the target is to be invoked
(in this case, print out a message to the system
<classname>Console</classname> detailing the name of the method). In the
<literal>Console</literal> detailing the name of the method). In the
tradition of good programming that says one should use only what one
needs and no more, Spring.NET has another type of advice that one can
use... if one only wants to do something <emphasis>before</emphasis> the
@@ -463,7 +480,7 @@
call the <literal>Proceed()</literal> method? The most expedient
solution simply is to use <emphasis>'before advice'</emphasis>.</para>
<sect3 id="aop-quickstart-going-deeper-before-advice">
<sect3 xml:id="aop-quickstart-going-deeper-before-advice">
<title>Before advice</title>
<para><emphasis>'before advice'</emphasis> is just that... it is
@@ -479,13 +496,13 @@
advice'</emphasis> is just what you need.</para>
<para><emphasis>'before advice'</emphasis> in Spring.NET is defined by
the <classname>IMethodBeforeAdvice</classname> interface in the
the <literal>IMethodBeforeAdvice</literal> interface in the
<literal>Spring.Aop</literal> namespace. Lets just dive in with an
example... we'll use the same scenario as before to keep things
simple. Let's define the <emphasis>'before advice'</emphasis>
implementation first.</para>
<programlisting> public class ConsoleLoggingBeforeAdvice : IMethodBeforeAdvice
<programlisting language="csharp"> public class ConsoleLoggingBeforeAdvice : IMethodBeforeAdvice
{
public void Before(MethodInfo method, object[] args, object target)
{
@@ -503,15 +520,15 @@
}</programlisting>
<para>Let's apply a single instance of the
<classname>ConsoleLoggingBeforeAdvice</classname> advice to the
<literal>ConsoleLoggingBeforeAdvice</literal> advice to the
invocation of the <literal>Execute()</literal> method of the
<classname>ServiceCommand</classname>. What follows is programmatic
<literal>ServiceCommand</literal>. What follows is programmatic
configuration; as you can see, its pretty much identical to the
previous version... the only difference is that we're using our new
<emphasis>'before advice'</emphasis> (encapsulated as an instance of
the <classname>ConsoleLoggingBeforeAdvice</classname> class).</para>
the <literal>ConsoleLoggingBeforeAdvice</literal> class).</para>
<programlisting> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingBeforeAdvice());
ICommand command = (ICommand) factory.GetProxy();
command.Execute();</programlisting>
@@ -529,7 +546,7 @@
advice'</emphasis>, with <emphasis>'before advice'</emphasis> there is
no chance of forgetting to call the <literal>Proceed()</literal>
method on the target, because one does not have access to the
<classname>IMethodInvocation</classname> (as is the case with
<literal>IMethodInvocation</literal> (as is the case with
<emphasis>'around advice'</emphasis>)... similarly, you cannot forget
to return the return value either.</para>
@@ -541,7 +558,7 @@
<para>Here is the Spring.NET XML configuration for applying our
<emphasis>'before advice'</emphasis> declaratively...</para>
<programlisting> &lt;object id="beforeAdvice"
<programlisting language="myxml"> &lt;object id="beforeAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/&gt;
&lt;object id="myServiceObject"
@@ -558,7 +575,7 @@
&lt;/object&gt;</programlisting>
</sect3>
<sect3 id="aop-quickstart-going-deeper-after-advice">
<sect3 xml:id="aop-quickstart-going-deeper-after-advice">
<title>After advice</title>
<para>Just as <emphasis>'before advice'</emphasis> defines advice that
@@ -567,12 +584,12 @@
role="bold">after</emphasis> a target has been executed.</para>
<para><emphasis>'after advice'</emphasis> in Spring.NET is defined by
the <classname>IAfterReturningAdvice</classname> interface in the
the <literal>IAfterReturningAdvice</literal> interface in the
<literal>Spring.Aop</literal> namespace. Again, lets just fire on
ahead with an example... again, we'll use the same scenario as before
to keep things simple.</para>
<programlisting> public class ConsoleLoggingAfterAdvice : IAfterReturningAdvice
<programlisting language="csharp"> public class ConsoleLoggingAfterAdvice : IAfterReturningAdvice
{
public void AfterReturning(
object returnValue, MethodInfo method, object[] args, object target)
@@ -592,17 +609,17 @@
}</programlisting>
<para>Let's apply a single instance of the
<classname>ConsoleLoggingAfterAdvice</classname> advice to the
<literal>ConsoleLoggingAfterAdvice</literal> advice to the
invocation of the <literal>Execute()</literal> method of the
<classname>ServiceCommand</classname>. What follows is programmatic
<literal>ServiceCommand</literal>. What follows is programmatic
configuration; as you can, its pretty much identical to the
<emphasis>'before advice'</emphasis> version (which in turn was pretty
much identical to the original <emphasis>'around advice'</emphasis>
version)... the only real difference is that we're using our new
<emphasis>'after advice'</emphasis> (encapsulated as an instance of
the <classname>ConsoleLoggingAfterAdvice</classname> class).</para>
the <literal>ConsoleLoggingAfterAdvice</literal> class).</para>
<programlisting> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingAfterAdvice());
ICommand command = (ICommand) factory.GetProxy();
command.Execute();</programlisting>
@@ -624,7 +641,7 @@
advice'</emphasis> there is no chance of forgetting to call the
<literal>Proceed()</literal> method on the target, because just like
<emphasis>'before advice'</emphasis> you don't have access to the
<classname>IMethodInvocation</classname>... similarly, although you
<literal>IMethodInvocation</literal>... similarly, although you
get access to the return value of the target, you cannot forget to
return the return value either. You can however change the state of
the return value, typically by setting some of its properties, or by
@@ -652,7 +669,7 @@
<para>Here is the Spring.NET XML configuration for applying the
<emphasis>'after advice'</emphasis> declaratively...</para>
<programlisting> &lt;object id="afterAdvice"
<programlisting language="myxml"> &lt;object id="afterAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"/&gt;
&lt;object id="myServiceObject"
@@ -669,7 +686,7 @@
&lt;/object&gt;</programlisting>
</sect3>
<sect3 id="aop-quickstart-going-deeper-throws-advice">
<sect3 xml:id="aop-quickstart-going-deeper-throws-advice">
<title>Throws advice</title>
<para>So far we've covered <emphasis>'around advice'</emphasis>,
@@ -697,13 +714,13 @@
possible uses cases is of course endless.</para>
<para>The <emphasis>'throws advice'</emphasis> type in Spring.NET is
defined by the <classname>IThrowsAdvice</classname> interface in the
defined by the <literal>IThrowsAdvice</literal> interface in the
<literal>Spring.Aop</literal> namespace... basically, one defines on
one's <emphasis>'throws advice'</emphasis> implementation class what
types of exception are going to be handled. Lets take a quick look at
the <classname>IThrowsAdvice</classname> interface...</para>
the <literal>IThrowsAdvice</literal> interface...</para>
<programlisting> public interface IThrowsAdvice : IAdvice
<programlisting language="csharp"> public interface IThrowsAdvice : IAdvice
{
}</programlisting>
@@ -714,7 +731,7 @@
point, so here is some simple Spring.NET style <emphasis>'throws
advice'</emphasis>...</para>
<programlisting> public class ConsoleLoggingThrowsAdvice : IThrowsAdvice
<programlisting language="csharp"> public class ConsoleLoggingThrowsAdvice : IThrowsAdvice
{
public void AfterThrowing(Exception ex)
{
@@ -724,11 +741,11 @@
<para>Lets also change the implementation of the
<literal>Execute()</literal> method of the
<classname>ServiceCommand</classname> class such that it throws an
<literal>ServiceCommand</literal> class such that it throws an
exception. This will allow the advice encapsulated by the above
<classname>ConsoleLoggingThrowsAdvice</classname> to kick in.</para>
<literal>ConsoleLoggingThrowsAdvice</literal> to kick in.</para>
<programlisting> public class ServiceCommand : ICommand
<programlisting language="csharp"> public class ServiceCommand : ICommand
{
public void Execute()
{
@@ -738,11 +755,11 @@
<para>Let's programmatically apply the <emphasis>'throws
advice'</emphasis> (an instance of our
<classname>ConsoleLoggingThrowsAdvice</classname>) to the invocation
<literal>ConsoleLoggingThrowsAdvice</literal>) to the invocation
of the <literal>Execute()</literal> method of the above
<classname>ServiceCommand</classname> class; to wit...</para>
<literal>ServiceCommand</literal> class; to wit...</para>
<programlisting> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingThrowsAdvice());
ICommand command = (ICommand) factory.GetProxy();
command.Execute();</programlisting>
@@ -754,19 +771,19 @@
Attempted to perform an unauthorized operation.</programlisting>
<para>As can be seen from the output, the
<classname>ConsoleLoggingThrowsAdvice</classname> kicked in when the
<literal>ConsoleLoggingThrowsAdvice</literal> kicked in when the
advised method invocation threw an exception. There are a number of
things to note about the
<classname>ConsoleLoggingThrowsAdvice</classname> advice class, so
<literal>ConsoleLoggingThrowsAdvice</literal> advice class, so
lets take them each in turn.</para>
<para>In Spring.NET, <emphasis>'throws advice'</emphasis> means that
you have to define a class that implements the
<classname>IThrowsAdvice</classname> interface. Then, for each type of
<literal>IThrowsAdvice</literal> interface. Then, for each type of
exception that your <emphasis>'throws advice'</emphasis> is going to
handle, you have to define a method with this signature...</para>
<programlisting> void AfterThrowing(Exception ex)</programlisting>
<programlisting language="csharp"> void AfterThrowing(Exception ex)</programlisting>
<para>Basically, your exception handling method has to be named
<literal>AfterThrowing</literal>. This name is important... your
@@ -779,19 +796,19 @@
in the future).</para>
<para>Your exception handling method must (at the very least) declare
a parameter that is an <classname>Exception</classname> type... this
parameter can be the root <classname>Exception</classname> class (as
a parameter that is an <literal>Exception</literal> type... this
parameter can be the root <literal>Exception</literal> class (as
in the case of the above example), or it can be an
<classname>Exception</classname> subclass if you only want to handle
<literal>Exception</literal> subclass if you only want to handle
certain types of exception. It is good practice to always make your
exception handling methods have an <classname>Exception</classname>
exception handling methods have an <literal>Exception</literal>
parameter that is the most specialized
<classname>Exception</classname> type possible... i.e. if you are
<literal>Exception</literal> type possible... i.e. if you are
applying <emphasis>'throws advice'</emphasis> to a method that could
only ever throw <classname>ArgumentException</classname>s, then
only ever throw <literal>ArgumentException</literal>s, then
declare the parameter of your exception handling method as...</para>
<programlisting> void AfterThrowing(ArgumentException ex)</programlisting>
<programlisting language="csharp"> void AfterThrowing(ArgumentException ex)</programlisting>
<para>Note that your exception handling method can have any return
type, but returning any value from a Spring.NET <emphasis>'throws
@@ -803,7 +820,7 @@
<para>Finally, here is the Spring.NET XML configuration for applying
the <emphasis>'throws advice'</emphasis> declaratively...</para>
<programlisting> &lt;object id="throwsAdvice"
<programlisting language="myxml"> &lt;object id="throwsAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"/&gt;
&lt;object id="myServiceObject"
@@ -830,14 +847,14 @@
wrapped exception in the body of one's exception handling method. One
can use this to implement some sort of exception translation or
exception scrubbing policy, in which implementation specific
exceptions (such as <classname>SqlException</classname> or
<classname>OracleException</classname> exceptions being thrown by an
exceptions (such as <literal>SqlException</literal> or
<literal>OracleException</literal> exceptions being thrown by an
advised data access object) get replaced with a business exception
that has meaning to the service objects in one's business layer. A toy
example of this type of <emphasis>'throws advice'</emphasis> can be
seen below.</para>
<programlisting> public class DataAccessExceptionScrubbingThrowsAdvice : IThrowsAdvice
<programlisting language="csharp"> public class DataAccessExceptionScrubbingThrowsAdvice : IThrowsAdvice
{
public void AfterThrowing (SqlException ex)
{
@@ -862,11 +879,11 @@
reference documentation, which describes how to declare an exception
handling method that gives one access to the above extra objects, and
how to declare multiple exception handling methods on the same
<classname>IThrowsAdvice</classname> implementation class (see <xref
<literal>IThrowsAdvice</literal> implementation class (see <xref
linkend="aop-introduction-advice-types-throws" />).</para>
</sect3>
<sect3 id="aop-quickstart-going-deeper-introduction-advice">
<sect3 xml:id="aop-quickstart-going-deeper-introduction-advice">
<title>Introductions (mixins)</title>
<para>In a nutshell, introductions are all about adding new state and
@@ -877,7 +894,7 @@
don't share the same inheritance hierarchy.</para>
</sect3>
<sect3 id="aop-quickstart-going-deeper-layering-advice">
<sect3 xml:id="aop-quickstart-going-deeper-layering-advice">
<title>Layering advice</title>
<para>The examples shown so far have all demonstrated the application
@@ -898,18 +915,18 @@
<para>Please do consult the class definitions for the following
previously defined advice types to see exactly what each advice type
implementation does... we're going to be using single instances of the
<classname>ConsoleLoggingAroundAdvice</classname>,
<classname>ConsoleLoggingBeforeAdvice</classname>,
<classname>ConsoleLoggingAfterAdvice</classname>, and
<classname>ConsoleLoggingThrowsAdvice</classname> advice to advise a
single instance of the <classname>ServiceCommand</classname>
<literal>ConsoleLoggingAroundAdvice</literal>,
<literal>ConsoleLoggingBeforeAdvice</literal>,
<literal>ConsoleLoggingAfterAdvice</literal>, and
<literal>ConsoleLoggingThrowsAdvice</literal> advice to advise a
single instance of the <literal>ServiceCommand</literal>
class.</para>
<para>You can find the following listing and executable application in
the AopQuickStart solution in the project
<literal>Spring.AopQuickStart.Step1</literal>.</para>
<programlisting> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
factory.AddAdvice(new ConsoleLoggingBeforeAdvice());
factory.AddAdvice(new ConsoleLoggingAfterAdvice());
factory.AddAdvice(new ConsoleLoggingThrowsAdvice());
@@ -924,7 +941,7 @@
the AopQuickStart solution in the project
<literal>Spring.AopQuickStart.Step2</literal>.</para>
<programlisting> &lt;object id="throwsAdvice"
<programlisting language="myxml"> &lt;object id="throwsAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"/&gt;
&lt;object id="afterAdvice"
type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"/&gt;
@@ -950,7 +967,7 @@
&lt;/object&gt;</programlisting>
</sect3>
<sect3 id="aop-quickstart-going-deeper-configuring-advice">
<sect3 xml:id="aop-quickstart-going-deeper-configuring-advice">
<title>Configuring advice</title>
<para>In case it is not immediately apparent, remember that advice is
@@ -978,14 +995,14 @@
</sect3>
</sect2>
<sect2 id="aop-quickstart-going-deeper-attribute-pointcuts">
<sect2 xml:id="aop-quickstart-going-deeper-attribute-pointcuts">
<title>Using Attributes to define Pointcuts</title>
<para></para>
</sect2>
</sect1>
<sect1 id="aop-quickstart-cookbook">
<sect1 xml:id="aop-quickstart-cookbook">
<title>The Spring.NET AOP Cookbook</title>
<para>The preceding treatment of Spring.NET AOP has (quite intentionally)
@@ -993,7 +1010,7 @@
Spring.NET AOP... this section of the Spring.NET AOP guide contains a
number of real world examples of the application of Spring.NET AOP.</para>
<sect2 id="aop-quickstart-cookbook-caching">
<sect2 xml:id="aop-quickstart-cookbook-caching">
<title>Caching</title>
<para>This example illustrates one of the more common usages of AOP...
@@ -1005,26 +1022,26 @@
it exists only in the database to satisfy referential integrity amongst
the various relations in the database schema. An example of such static
(and typically immutable) reference data would be a collection of
<classname>Country</classname> objects (comprising a country name and a
<literal>Country</literal> objects (comprising a country name and a
code). What we would like to do is suck in the collection of
<classname>Country</classname> objects and then pin them in a cache.
<literal>Country</literal> objects and then pin them in a cache.
This saves us having to hit the back end database again and again every
time we need to reference a country in our application (for example, to
populate dropdown controls in a Windows Forms desktop
application).</para>
<para>The Data Access Object (DAO) that will load the collection of
<classname>Country</classname> objects is called
<classname>AdoCountryDao</classname> (it is an implementation of the
<literal>Country</literal> objects is called
<literal>AdoCountryDao</literal> (it is an implementation of the
data-access-technology agnostic DAO interface called
<classname>ICountryDao</classname>). The implementation of the
<classname>AdoCountryDao</classname> is quite simple, in that every time
<literal>ICountryDao</literal>). The implementation of the
<literal>AdoCountryDao</literal> is quite simple, in that every time
the <literal>FindAllCountries</literal> instance method is called, an
instance will query the database for an
<classname>IDataReader</classname> and hydrate zero or more
<classname>Country</classname> objects using the returned data.</para>
<literal>IDataReader</literal> and hydrate zero or more
<literal>Country</literal> objects using the returned data.</para>
<programlisting> public class AdoCountryDao : ICountryDao
<programlisting language="csharp"> public class AdoCountryDao : ICountryDao
{
public IList FindAllCountries ()
{
@@ -1044,15 +1061,15 @@
<para>The mechanism that this example is going to use to identify (or
pick out) areas in our application that we would like to apply caching
to is a .NET <classname>Attribute</classname>. Spring.NET ships with a
number of useful custom .NET <classname>Attribute</classname>
to is a .NET <literal>Attribute</literal>. Spring.NET ships with a
number of useful custom .NET <literal>Attribute</literal>
implementations, one of which is the cunningly named
<classname>CacheAttribute</classname>. In the specific case of this
<literal>CacheAttribute</literal>. In the specific case of this
example, we are simply going to decorate the definition of the
<literal>FindAllCountries</literal> instance method with the
<classname>CacheAttribute</classname>.</para>
<literal>CacheAttribute</literal>.</para>
<programlisting> public class AdoCountryDao : ICountryDao
<programlisting language="csharp"> public class AdoCountryDao : ICountryDao
{
[Cache]
public IList FindAllCountries ()
@@ -1067,7 +1084,7 @@
applied using Spring.NET AOP (see <xref linkend="springair" />).</para>
</sect2>
<sect2 id="aop-quickstart-cookbook-performance-monitoring-windows">
<sect2 xml:id="aop-quickstart-cookbook-performance-monitoring-windows">
<title>Performance Monitoring</title>
<para>This recipe show how easy it is to instrument the classes and
@@ -1076,7 +1093,7 @@
counters to display and track the performance data.</para>
</sect2>
<sect2 id="aop-quickstart-cookbook-retry">
<sect2 xml:id="aop-quickstart-cookbook-retry">
<title>Retry Rules</title>
<para>This final recipe describes a simple (but really quite useful)
@@ -1087,7 +1104,7 @@
</sect2>
</sect1>
<sect1 id="aop-quickstart-best-practices">
<sect1 xml:id="aop-quickstart-best-practices">
<title>Spring.NET AOP Best Practices</title>
<para>Spring.NET AOP is an 80% AOP solution, in that it only tries to

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="background">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="background" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Background information</title>
<sect1 id="background-ioc">
<sect1 xml:id="background-ioc">
<title>Inversion of Control</title>
<para>In early 2004, Martin Fowler asked the readers of his site: when

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="dao">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="dao" xmlns="http://docbook.org/ns/docbook" version="5">
<title>DAO support</title>
<section id="dao-introduction">
<section xml:id="dao-introduction">
<title>Introduction</title>
<para>Spring promotes the use of data access interfaces in your
@@ -35,17 +52,17 @@
catching exceptions that are specific to each technology.</para>
</section>
<section id="dao-exceptions">
<section xml:id="dao-exceptions">
<title>Consistent exception hierarchy</title>
<para>Database exceptions in the ADO.NET API are not consistent across
providers. The .NET 1.1 BCL did not provide a common base class for
ADO.NET exceptions. As such you were required to handle exceptions
specific to each provider such as
<classname>System.Data.SqlClient.SqlException</classname> or
<classname>System.Data.OracleClient.OracleException</classname>. The .NET
<literal>System.Data.SqlClient.SqlException</literal> or
<literal>System.Data.OracleClient.OracleException</literal>. The .NET
2.0 BCL improved in this regard by introducing a common base class for
exceptions, <classname>System.Data.Common.DbException</classname>. However
exceptions, <literal>System.Data.Common.DbException</literal>. However
the common DbException is not very portable either as it provides a vendor
specific error code as the underlying piece of information as to what went
wrong. This error code is different across providers for the same
@@ -54,10 +71,10 @@
<para>To promote writing portable and descriptive exception handling code
Spring provides a convenient translation from technology specific
exceptions like <classname>System.Data.SqlClient.SqlException</classname>
or <classname>System.Data.OracleClient.OracleException</classname> to its
exceptions like <literal>System.Data.SqlClient.SqlException</literal>
or <literal>System.Data.OracleClient.OracleException</literal> to its
own exception hierarchy with the
<classname>Spring.Dao.DataAccessException</classname> as the root
<literal>Spring.Dao.DataAccessException</literal> 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>
@@ -83,13 +100,13 @@
<para>(Please note that the class hierarchy detailed in the above image
shows only a subset of the whole, rich,
<classname>DataAccessException</classname> hierarchy.)</para>
<literal>DataAccessException</literal> hierarchy.)</para>
<para>The exception translation functionality is in the namespace
Spring.Data.Support and is based on the interface
<literal>IAdoExceptionTranslator</literal> shown below.</para>
<programlisting>public interface IAdoExceptionTranslator
<programlisting language="csharp">public interface IAdoExceptionTranslator
{
DataAccessException Translate( string task, string sql, Exception exception );
}</programlisting>
@@ -131,7 +148,7 @@
codes that map to a
<literal>DataIntegrityViolationException</literal>.</para>
<para><programlisting>&lt;objects xmlns='http://www.springframework.net'&gt;
<para><programlisting language="myxml">&lt;objects xmlns='http://www.springframework.net'&gt;
&lt;alias name='SqlServer-2.0' alias='SqlServer2005'/&gt;
@@ -153,7 +170,7 @@
periods in the name is a workaround.</para>
<para>Another way to customize the mappings of error codes to exceptions
is to subclass <classname>ErrorCodeExceptionTranslator</classname> and
is to subclass <literal>ErrorCodeExceptionTranslator</literal> and
override the method, <literal>DataAccessException
TranslateException(string task, string sql, string errorCode, Exception
exception)</literal>. This will be called before referencing the metadata
@@ -297,26 +314,26 @@
<itemizedlist>
<listitem>
<para><classname>AdoDaoSupport</classname> - super class for ADO.NET
<para><literal>AdoDaoSupport</literal> - super class for ADO.NET
data access objects. Requires a
<interfacename>DbProvider</interfacename> to be provided; in turn,
this class provides a <classname>AdoTemplate</classname> instance
<literal>DbProvider</literal> to be provided; in turn,
this class provides a <literal>AdoTemplate</literal> instance
initialized from the supplied
<interfacename>DbProvider</interfacename> to subclasses. See the
<literal>DbProvider</literal> to subclasses. See the
documentation for <literal>AdoTemplate</literal> for more
information.</para>
</listitem>
<listitem>
<para><classname>HibernateDaoSupport</classname> - super class for
<para><literal>HibernateDaoSupport</literal> - super class for
NHibernate data access objects. Requires a
<interfacename>ISessionFactory</interfacename> to be provided; in
turn, this class provides a <classname>HibernateTemplate</classname>
<literal>ISessionFactory</literal> to be provided; in
turn, this class provides a <literal>HibernateTemplate</literal>
instance initialized from the supplied
<interfacename>SessionFactory</interfacename> to subclasses. Can
<literal>SessionFactory</literal> to subclasses. Can
alternatively be initialized directly via a
<classname>HibernateTemplate</classname>, to reuse the latter's
settings like <interfacename>SessionFactory</interfacename>, flush
<literal>HibernateTemplate</literal>, to reuse the latter's
settings like <literal>SessionFactory</literal>, flush
mode, exception translator, etc. This is contained in a download
separate from the main Spring.NET distribution.</para>
</listitem>

View File

@@ -1,5 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="data-quickstart">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="data-quickstart" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Data Access QuickStart</title>
<section>
@@ -14,40 +31,39 @@
<para>The quick start contains pseudo DAO objects and a collection of
NUnit tests to exercise them rather than a full blown application. To run
the tests from within VS.NET install <ulink
url="http://www.testdriven.net/"><link
linkend="???">TestDriven.NET</link></ulink>, <ulink
url="http://www.testdriven.net/">TestDriven.NET</ulink>, <ulink
url="http://www.jetbrains.com/resharper/">ReSharper</ulink>, or an
equivalent . The listing of DAO classes and the parts of Spring.Data that
they demonstrate is shown below.</para>
<itemizedlist>
<listitem>
<para><classname>CommandCallbackDao</classname> - Use of the
<para><literal>CommandCallbackDao</literal> - Use of the
ICommandCallback and CommandCallbackDelegate</para>
</listitem>
<listitem>
<para><classname>ResultSetExtractorDao</classname> - Use of
<para><literal>ResultSetExtractorDao</literal> - Use of
IResultSetExtractor and ResultSetExtractorDelegate</para>
</listitem>
<listitem>
<para><classname>RowCallbackDao</classname> - Use of IRowCallback and
<para><literal>RowCallbackDao</literal> - Use of IRowCallback and
RowCallbackDelegate</para>
</listitem>
<listitem>
<para><classname>RowMapperDao</classname> - Use of IRowMapper and
<para><literal>RowMapperDao</literal> - Use of IRowMapper and
RowMapperDelegate</para>
</listitem>
<listitem>
<para><classname>QueryForObject</classname> - Use of QueryForObject
<para><literal>QueryForObject</literal> - Use of QueryForObject
method.</para>
</listitem>
<listitem>
<para><classname>StoredProcDao</classname> - Use of
<para><literal>StoredProcDao</literal> - Use of
Spring.Data.Objects.StoredProcedure</para>
</listitem>
</itemizedlist>
@@ -63,7 +79,7 @@
database connection string. The listing in
DataQuickStart.GenericTemplate.ExampleTests.xml is shown below</para>
<programlisting>&lt;objects xmlns="http://www.springframework.net"
<programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"
xmlns:db="http://www.springframework.net/database"&gt;
&lt;db:provider id="dbProvider"
@@ -93,7 +109,7 @@
which is responsible for performing data access operations. This is
declared in ExampleTest.xml as shown below</para>
<programlisting> &lt;object id="adoTemplate" type="Spring.Data.Generic.AdoTemplate, Spring.Data"&gt;
<programlisting language="myxml"> &lt;object id="adoTemplate" type="Spring.Data.Generic.AdoTemplate, Spring.Data"&gt;
&lt;property name="DbProvider" ref="dbProvider"/&gt;
&lt;property name="DataReaderWrapperType" value="Spring.Data.Support.NullMappingDataReader, Spring.Data"/&gt;
&lt;/object&gt;
@@ -103,7 +119,7 @@
previously defined. Also the property DataReaderWrapper is set to the
NullMappingDataReader that ships with Spring. This provides convenient
default values for null values returned from the database. To read
more about AdoTemplate, refer to the chapter, <link linkend="???">Data
more about AdoTemplate, refer to the chapter, <link linkend="ado">Data
access using ADO.NET</link>.</para>
</section>
</section>
@@ -114,7 +130,7 @@
<para>The code that exercises the use of a CommandCallback is shown
below</para>
<programlisting> [Test]
<programlisting language="csharp"> [Test]
public void CallbackDaoTest()
{
CommandCallbackDao commandCallbackDao = ctx["commandCallbackDao"] as CommandCallbackDao;
@@ -124,7 +140,7 @@
<para>The configuration of the CommandCallbackDao is shown below</para>
<programlisting> &lt;object id="commandCallbackDao" type="Spring.DataQuickStart.Dao.GenericTemplate.CommandCallbackDao, Spring.DataQuickStart"&gt;
<programlisting language="myxml"> &lt;object id="commandCallbackDao" type="Spring.DataQuickStart.Dao.GenericTemplate.CommandCallbackDao, Spring.DataQuickStart"&gt;
&lt;property name="AdoTemplate" ref="adoTemplate"/&gt;
&lt;/object&gt;</programlisting>
@@ -134,7 +150,7 @@
size of the result set returned etc. The implementation of the
FindCountWithPostalCode is shown below</para>
<programlisting> public virtual int FindCountWithPostalCodeWithDelegate(string postalCode)
<programlisting language="csharp"> public virtual int FindCountWithPostalCodeWithDelegate(string postalCode)
{
// Using anonymous delegates allows you to easily reference the
// surrounding parameters for use with the DbCommand processing.

View File

@@ -1,13 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="dbprovider">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="dbprovider" xmlns="http://docbook.org/ns/docbook" version="5">
<title>DbProvider</title>
<section id="dbprovider-introduction">
<section xml:id="dbprovider-introduction">
<title>Introduction</title>
<para>Spring provides a generic factory for creating ADO.NET API artifacts
such as <code><classname>IDbConnection</classname></code> and
<code><classname>IDbCommand</classname></code>. The factory API is very
such as <code><literal>IDbConnection</literal></code> and
<code><literal>IDbCommand</literal></code>. The factory API is very
similar to the one introduced in .NET 2.0 but adds extra metadata needed
by Spring to support features provided by its DAO/ADO.NET framework such
as error code translation to a DAO exception hierarchy. The factory itself
@@ -39,15 +56,15 @@
calling context.</para>
</section>
<section id="dbprovider-dbprovider">
<section xml:id="dbprovider-dbprovider">
<title>IDbProvider and DbProviderFactory</title>
<para>The <code><interfacename>IDbProvider</interfacename></code> API is
<para>The <code><literal>IDbProvider</literal></code> API is
shown below and should look familiar to anyone using .NET 2.0 data
providers. Note that Spring's DbProvider abstraction can be used on .NET
1.1 in addition to .NET 2.0</para>
<programlisting> public interface IDbProvider
<programlisting language="csharp"> public interface IDbProvider
{
IDbCommand CreateCommand();
@@ -89,7 +106,7 @@
create the string for a IDataParameter.ParameterName, typically contained
inside a IDataParameterCollection.</para>
<para>The class <classname>DbProviderFactory</classname> creates
<para>The class <literal>DbProviderFactory</literal> creates
IDbProvider instances given a provider name. The connection string
property will be used to set the IDbConnection returned by the factory if
present. The provider names, and corresponding database, currently
@@ -242,17 +259,17 @@
<para>An example using DbProviderFactory is shown below</para>
<programlisting>IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");</programlisting>
<programlisting language="csharp">IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");</programlisting>
<para>The default definitions of the providers are contained in the
assembly resource
<code>assembly://Spring.Data/Spring.Data.Common/dbproviders.xml</code>.
Future additions to round out the database coverage are forthcoming. The
current crude mechanism to add additional providers, or to apply any
standard Spring <interfacename>IApplicationContext</interfacename>
standard Spring <literal>IApplicationContext</literal>
functionality, such as applying AOP advice, is to set the public static
property DBPROVIDER_ADDITIONAL_RESOURCE_NAME in
<classname>DbProviderFactory</classname> to a Spring resource location.
<literal>DbProviderFactory</literal> to a Spring resource location.
The default value is <code>file://dbProviders.xml</code>. (That isn't a
typo, there is a difference in case with the name of the embedded
resource). This crude mechanism will eventually be replaced with one based
@@ -264,7 +281,7 @@
application, you should add an assembly redirect of the form shown
below.</para>
<programlisting>&lt;dependentAssembly&gt;
<programlisting language="myxml">&lt;dependentAssembly&gt;
&lt;assemblyIdentity name="MySql.Data"
publicKeyToken="c5687fc88969c44d"
culture="neutral"/&gt;
@@ -283,7 +300,7 @@
below in the typical case of using it to specify the DbProvider property
on an AdoTemplate.</para>
<programlisting>&lt;objects xmlns='http://www.springframework.net'
<programlisting language="myxml">&lt;objects xmlns='http://www.springframework.net'
xmlns:db="http://www.springframework.net/database"&gt;
&lt;db:provider id="DbProvider"
@@ -302,7 +319,7 @@
the rest of the Spring configuration locations as described in previous
chapters.</para>
<programlisting>&lt;configuration&gt;
<programlisting language="myxml">&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
@@ -335,7 +352,7 @@
<para>An example of such a setting is shown below</para>
<programlisting>&lt;configuration&gt;
<programlisting language="myxml">&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;section name='context' type='Spring.Context.Support.ContextHandler, Spring.Core'/&gt;
@@ -367,7 +384,7 @@
<para>Where <literal>Dao.xml</literal> has a connection string as shown
below</para>
<programlisting>&lt;objects xmlns='http://www.springframework.net'
<programlisting language="myxml">&lt;objects xmlns='http://www.springframework.net'
xmlns:db="http://www.springframework.net/database"&gt;
&lt;db:provider id="DbProvider"
@@ -391,17 +408,17 @@
information.</para>
</section>
<section id="dbprovider-additional">
<section xml:id="dbprovider-additional">
<title>Additional IDbProvider implementations</title>
<para>Spring provides some convenient implementations of the IDbProvider
interface that add addtional behavior on top of the standard
implementation.</para>
<section id="dbprovider-usercredentials">
<section xml:id="dbprovider-usercredentials">
<title>UserCredentialsDbProvider</title>
<para>This <classname>UserCredentialsDbProvider</classname> will allow
<para>This <literal>UserCredentialsDbProvider</literal> will allow
you to change the username and password of a database connection at
runtime. The API contains the properties <literal>Username</literal> and
<literal>Password</literal> which are used as the default strings
@@ -416,7 +433,7 @@
You may retrieve the user information from an HTTP session for example.
Example configuration and usage is shown below</para>
<programlisting>&lt;object id="DbProvider" type="Spring.Data.Common.UserCredentialsDbProvider, Spring.Data"&gt;
<programlisting language="myxml">&lt;object id="DbProvider" type="Spring.Data.Common.UserCredentialsDbProvider, Spring.Data"&gt;
&lt;property name="TargetDbProvider" ref="targetDbProvider"/&gt;
&lt;property name="Username" value="User ID=defaultName"/&gt;
&lt;property name="Password" value="Password=defaultPass"/&gt;
@@ -431,7 +448,7 @@
of the type <literal>UserCredentialsDbProvider</literal> instead of
<literal>IDbProvider</literal>.</para>
<programlisting>userCredentialsDbProvider.SetCredentialsForCurrentThread("User ID=springqa", "Password=springqa");</programlisting>
<programlisting language="csharp">userCredentialsDbProvider.SetCredentialsForCurrentThread("User ID=springqa", "Password=springqa");</programlisting>
<para><literal>UserCredentialsDbProvider's</literal> has a base class,
<literal>DelegatingDbProvider</literal>, and is intended for you to use
@@ -442,21 +459,21 @@
to the target <literal>IDbProvider</literal>.</para>
</section>
<section id="dbprovider-multidelegating">
<section xml:id="dbprovider-multidelegating">
<title>MultiDelegatingDbProvider</title>
<para>There are use-cases in which there will need to be a runtime
selection of the database to connect to among many possible candidates.
This is often the case where the same schema is installed in separate
databases for different clients. The
<classname>MultiDelegatingDbProvider</classname> implements the
<classname>IDbProvider</classname> interface and provides an abstraction
<literal>MultiDelegatingDbProvider</literal> implements the
<literal>IDbProvider</literal> interface and provides an abstraction
to the multiple databases and can be used in DAO layer such that the DAO
layer is unaware of the switching between databases.
<classname>MultiDelegatingDbProvider</classname> does its job by looking
<literal>MultiDelegatingDbProvider</literal> does its job by looking
into thread local storage under the key dbProviderName. This storage
location stores the name of the dbProvider that is to be used for
processing the request. <classname>MultiDelegatingDbProvider</classname>
processing the request. <literal>MultiDelegatingDbProvider</literal>
is configured using the dictionary property
<literal>TargetDbProviders</literal>. The key of this dictionary
contains the name of a dbProvider and its value is a dbProvider object.

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="expressions">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="expressions" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Expression Evaluation</title>
<sect1 id="expressions-introduction">
<sect1 xml:id="expressions-introduction">
<title>Introduction</title>
<para>The Spring.Expressions namespace provides a powerful expression
@@ -33,12 +50,12 @@
additional example usage.</para>
</sect1>
<sect1 id="expressions-evaluating">
<sect1 xml:id="expressions-evaluating">
<title>Evaluating Expressions</title>
<para>The simplest, but not the most efficient way to perform expression
evaluation is by using one of the static convenience methods of the
<classname>ExpressionEvaluator</classname> class:<programlisting>public static object GetValue(object root, string expression);
<literal>ExpressionEvaluator</literal> class:<programlisting language="csharp">public static object GetValue(object root, string expression);
public static object GetValue(object root, string expression, IDictionary variables)
@@ -49,8 +66,8 @@ public static void SetValue(object root, string expression, IDictionary variable
argument) will be evaluated against. The third argument is used to support
variables in the expression and will be discussed later. Simple usage to
get the value of an object property is shown below using the
<classname>Inventor</classname> class. You can find the class listing in
section <xref linkend="expressions-classes" />. <programlisting>Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian");
<literal>Inventor</literal> class. You can find the class listing in
section <xref linkend="expressions-classes" />. <programlisting language="csharp">Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian");
tesla.PlaceOfBirth.City = "Smiljan";
@@ -61,39 +78,39 @@ string evaluatedCity = (string) ExpressionEvaluator.GetValue(tesla, "PlaceOfBirt
is 'Smiljan'. A period is used to navigate the nested properties of the
object. Similarly to set the property of an object, say we want to rewrite
history and change Tesla's city of birth, we would simply add the
following line <programlisting>ExpressionEvaluator.SetValue(tesla, "PlaceOfBirth.City", "Novi Sad");</programlisting></para>
following line <programlisting language="csharp">ExpressionEvaluator.SetValue(tesla, "PlaceOfBirth.City", "Novi Sad");</programlisting></para>
<para>A much better way to evaluate expressions is to parse them once and
then evaluate as many times as you want
using<classname>Expression</classname>class. Unlike
<classname>ExpressionEvaluator</classname>, which parses expression every
time you invoke one of its methods, <classname>Expression</classname>
using<literal>Expression</literal>class. Unlike
<literal>ExpressionEvaluator</literal>, which parses expression every
time you invoke one of its methods, <literal>Expression</literal>
class will cache the parsed expression for increased performance. The
methods of this class are listed below: <programlisting>public static IExpression Parse(string expression)
methods of this class are listed below: <programlisting language="csharp">public static IExpression Parse(string expression)
public override object Get(object context, IDictionary variables)
public override void Set(object context, IDictionary variables, object newValue)</programlisting>
The retrieval of the Name property in the previous example using the
Expression class is shown below <programlisting>IExpression exp = Expression.Parse("Name");
Expression class is shown below <programlisting language="csharp">IExpression exp = Expression.Parse("Name");
string evaluatedName = (string) exp.GetValue(tesla, null);</programlisting></para>
<para>The difference in performance between the two approaches, when
evaluating the same expression many times, is several orders of magnitude,
so you should only use convenience methods of the
<classname>ExpressionEvaluator</classname> class when you are doing
<literal>ExpressionEvaluator</literal> class when you are doing
one-off expression evaluations. In all other cases you should parse the
expression first and then evaluate it as many times as you need.</para>
<para>There are a few exception classes to be aware of when using the
<classname>ExpressionEvaluator</classname>. These are
<classname>InvalidPropertyException</classname>, when you refer to a
<literal>ExpressionEvaluator</literal>. These are
<literal>InvalidPropertyException</literal>, when you refer to a
property that doesn't exist,
<classname>NullValueInNestedPathException</classname>, when a null value
<literal>NullValueInNestedPathException</literal>, when a null value
is encountered when traversing through the nested property list, and
<classname>ArgumentException</classname> and
<classname>NotSupportedException</classname> when you pass in values that
<literal>ArgumentException</literal> and
<literal>NotSupportedException</literal> when you pass in values that
are in error in some other manner.</para>
<para>The expression language is based on a grammar and uses <ulink
@@ -109,10 +126,10 @@ string evaluatedName = (string) exp.GetValue(tesla, null);</programlisting></par
assemblies, which will remove this requirement.</para>
</sect1>
<sect1 id="expressions-language-ref">
<sect1 xml:id="expressions-language-ref">
<title>Language Reference</title>
<sect2 id="expressions-literals">
<sect2 xml:id="expressions-literals">
<title>Literal expressions</title>
<para>The types of literal expressions supported are strings, dates,
@@ -121,7 +138,7 @@ string evaluatedName = (string) exp.GetValue(tesla, null);</programlisting></par
the backslash character. The following listing shows simple usage of
literals. Typically they would not be used in isolation like this, but
as part of a more complex expression, for example using a literal on one
side of a logical comparison operator. <programlisting>string helloWorld = (string) ExpressionEvaluator.GetValue(null, "'Hello World'"); // evals to "Hello World"
side of a logical comparison operator. <programlisting language="csharp">string helloWorld = (string) ExpressionEvaluator.GetValue(null, "'Hello World'"); // evals to "Hello World"
string tonyPizza = (string) ExpressionEvaluator.GetValue(null, "'Tony\\'s Pizza'"); // evals to "Tony's Pizza"
@@ -140,29 +157,29 @@ object nullValue = ExpressionEvaluator.GetValue(null, "null");</programlisting>
Note that the extra backslash character in Tony's Pizza is to satisfy C#
escape syntax. Numbers support the use of the negative sign, exponential
notation, and decimal points. By default real numbers are parsed using
<classname>Double.Parse</classname> unless the format character "M" or
"F" is supplied, in which case <classname>Decimal.Parse</classname> and
<classname>Single.Parse</classname> would be used respectfully. As shown
<literal>Double.Parse</literal> unless the format character "M" or
"F" is supplied, in which case <literal>Decimal.Parse</literal> and
<literal>Single.Parse</literal> would be used respectfully. As shown
above, if two arguments are given to the date literal then
<classname>DateTime.ParseExact</classname> will be used. Note that all
<literal>DateTime.ParseExact</literal> will be used. Note that all
parse methods of classes that are used internally reference the
<classname>CultureInfo.InvariantCulture</classname>.</para>
<literal>CultureInfo.InvariantCulture</literal>.</para>
</sect2>
<!-- PROPERTIES -->
<sect2 id="expressions-properties">
<sect2 xml:id="expressions-properties">
<title>Properties, Arrays, Lists, Dictionaries, Indexers</title>
<para>As shown in the previous example in <xref
linkend="expressions-evaluating" />, navigating through properties is
easy, just use a period to indicate a nested property value. The
instances of <classname>Inventor</classname> class,
instances of <literal>Inventor</literal> class,
<emphasis>pupin</emphasis> and <emphasis>tesla</emphasis>, were
populated with data listed in section <xref
linkend="expressions-classes" />. To navigate "down" and get Tesla's
year of birth and Pupin's city of birth the following expressions are
used <programlisting>int year = (int) ExpressionEvaluator.GetValue(tesla, "DOB.Year")); // 1856
used <programlisting language="csharp">int year = (int) ExpressionEvaluator.GetValue(tesla, "DOB.Year")); // 1856
string city = (string) ExpressionEvaluator.GetValue(pupin, "PlaCeOfBirTh.CiTy"); // "Idvor"</programlisting>
For the sharp-eyed, that isn't a typo in the property name for place of
@@ -170,7 +187,7 @@ string city = (string) ExpressionEvaluator.GetValue(pupin, "PlaCeOfBirTh.CiTy");
evaluation is case insensitive.</para>
<para>The contents of arrays and lists are obtained using square bracket
notation. <programlisting>// Inventions Array
notation. <programlisting language="csharp">// Inventions Array
string invention = (string) ExpressionEvaluator.GetValue(tesla, "Inventions[3]"); // "Induction motor"
// Members List
@@ -182,7 +199,7 @@ string invention = (string) ExpressionEvaluator.GetValue(ieee, "Members[0].Inven
<para>The contents of dictionaries are obtained by specifying the
literal key value within the brackets. In this case, because keys for
the <emphasis>Officers</emphasis> dictionary are strings, we can specify
string literal.<programlisting>// Officer's Dictionary
string literal.<programlisting language="csharp">// Officer's Dictionary
Inventor pupin = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers['president']";
string city = (string) ExpressionEvaluator.GetValue(ieee, "Officers['president'].PlaceOfBirth.City"); // "Idvor"
@@ -196,7 +213,7 @@ ExpressionEvaluator.SetValue(ieee, "Officers['advisors'][0].PlaceOfBirth.Country
<para>Indexers are similarly referenced using square brackets. The
following is a small example that shows the use of indexers.
Multidimensional indexers are also supported. <programlisting>public class Bar
Multidimensional indexers are also supported. <programlisting language="csharp">public class Bar
{
private int[] numbers = new int[] {1, 2, 3};
@@ -223,7 +240,7 @@ ExpressionEvaluator.SetValue(bar, "[1]", 3); // set value to 3</programlisting>
items with curly brackets:<programlisting>{1, 2, 3, 4, 5}
{'abc', 'xyz'}</programlisting> If you want to ensure that a strongly typed
array is initialized instead of a weakly typed list, you can use array
initializer instead: <programlisting>new int[] {1, 2, 3, 4, 5}
initializer instead: <programlisting language="csharp">new int[] {1, 2, 3, 4, 5}
new string[] {'abc', 'xyz'}</programlisting></para>
<para>Dictionary definition syntax is a bit different: you need to use
@@ -243,13 +260,13 @@ new string[] {'abc', 'xyz'}</programlisting></para>
</sect3>
</sect2>
<sect2 id="expressions-methods">
<sect2 xml:id="expressions-methods">
<title>Methods</title>
<para>Methods are invoked using typical C# programming syntax. You may
also invoke methods on literals.</para>
<programlisting>//string literal
<programlisting language="csharp">//string literal
char[] chars = (char[]) ExpressionEvaluator.GetValue(null, "'test'.ToCharArray(1, 2)")) // 't','e'
//date literal
@@ -260,23 +277,23 @@ int year = (int) ExpressionEvaluator.GetValue(null, "date('1974/08/24').AddYears
ExpressionEvaluator.GetValue(ieee, "Members[0].GetAge(date('2005-01-01')") // 149 (eww..a big anniversary is coming up ;)</programlisting>
</sect2>
<sect2 id="expressions-operators">
<sect2 xml:id="expressions-operators">
<title>Operators</title>
<sect3 id="expressions-relational">
<sect3 xml:id="expressions-relational">
<title>Relational operators</title>
<para>The relational operators; equal, not equal, less than, less than
or equal, greater than, and greater than or equal are supported using
standard operator notation. These operators take into account if the
object implements the <classname>IComparable</classname> interface.
object implements the <literal>IComparable</literal> interface.
Enumerations are also supported but you will need to register the
enumeration type, as described in Section <xref
linkend="expressions-typeregistration" />, in order to use an
enumeration value in an expression if it is not contained in the
mscorlib.</para>
<programlisting>ExpressionEvaluator.GetValue(null, "2 == 2") // true
<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "2 == 2") // true
ExpressionEvaluator.GetValue(null, "date('1974-08-24') != DateTime.Today") // true
@@ -286,12 +303,12 @@ ExpressionEvaluator.GetValue(null, "DateTime.Today &lt;= date('1974-08-24')") //
ExpressionEvaluator.GetValue(null, "'Test' &gt;= 'test'") // true</programlisting>
<para>Enumerations can be evaluated as shown below <programlisting>FooColor fColor = new FooColor();
<para>Enumerations can be evaluated as shown below <programlisting language="csharp">FooColor fColor = new FooColor();
ExpressionEvaluator.SetValue(fColor, "Color", KnownColor.Blue);
bool trueValue = (bool) ExpressionEvaluator.GetValue(fColor, "Color == KnownColor.Blue"); //true</programlisting>
Where FooColor is the following class. <programlisting>public class FooColor
Where FooColor is the following class. <programlisting language="csharp">public class FooColor
{
private KnownColor knownColor;
@@ -308,7 +325,7 @@ bool trueValue = (bool) ExpressionEvaluator.GetValue(fColor, "Color == KnownColo
<emphasis>like</emphasis> and <emphasis>between</emphasis>, as well as
<emphasis>is</emphasis> and <emphasis>matches</emphasis> operators,
which allow you to test if object is of a specific type or if the
value matches a regular expression.<programlisting>ExpressionEvaluator.GetValue(null, "3 in {1, 2, 3, 4, 5}") // true
value matches a regular expression.<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "3 in {1, 2, 3, 4, 5}") // true
ExpressionEvaluator.GetValue(null, "'Abc' like '[A-Z]b*'") // true
@@ -329,13 +346,13 @@ ExpressionEvaluator.GetValue(null, @"'5.00' matches '^-?\d+(\.\d{2})?$'") // tr
<emphasis>like</emphasis> operator pattern string.</para>
</sect3>
<sect3 id="expressions-logical">
<sect3 xml:id="expressions-logical">
<title>Logical operators</title>
<para>The logical operators that are supported are
<emphasis>and</emphasis>, <emphasis>or</emphasis>, and
<emphasis>not</emphasis>. Their use is demonstrated
below<programlisting>// AND
below<programlisting language="csharp">// AND
bool falseValue = (bool) ExpressionEvaluator.GetValue(null, "true and false"); //false
string expression = @"IsMember('Nikola Tesla') and IsMember('Mihajlo Pupin')";
@@ -355,7 +372,7 @@ string expression = @"IsMember('Nikola Tesla') and !IsMember('Mihajlo Pupin')";
bool falseValue = (bool) ExpressionEvaluator.GetValue(ieee, expression);</programlisting></para>
</sect3>
<sect3 id="expressions-math">
<sect3 xml:id="expressions-math">
<title>Mathematical operators</title>
<para>The addition operator can be used on numbers, strings and dates.
@@ -363,7 +380,7 @@ bool falseValue = (bool) ExpressionEvaluator.GetValue(ieee, expression);</progra
division can be used only on numbers. Other mathematical operators
supported are modulus (%) and exponential power (^). Standard operator
precedence is enforced. These operators are demonstrated below
<programlisting>// Addition
<programlisting language="csharp">// Addition
int two = (int)ExpressionEvaluator.GetValue(null, "1 + 1"); // 2
String testString = (String)ExpressionEvaluator.GetValue(null, "'test' + ' ' + 'string'"); //'test string'
@@ -407,7 +424,7 @@ int minusFortyFive = (int) ExpressionEvaluator.GetValue(null, "1+2-3*8^2/2/2");
</sect3>
</sect2>
<sect2 id="expressions-assignment">
<sect2 xml:id="expressions-assignment">
<title>Assignment</title>
<para>Setting of a property is done by using the assignment operator.
@@ -416,7 +433,7 @@ int minusFortyFive = (int) ExpressionEvaluator.GetValue(null, "1+2-3*8^2/2/2");
<literal>SetValue</literal> offers the same functionality. Assignment in
this manner is useful when combining multiple operators in an expression
list, discussed in the next section. Some examples of assignment are
shown below <programlisting>Inventor inventor = new Inventor();
shown below <programlisting language="csharp">Inventor inventor = new Inventor();
String aleks = (String) ExpressionEvaluator.GetValue(inventor, "Name = 'Aleksandar Seovic'");
DateTime dt = (DateTime) ExpressionEvaluator.GetValue(inventor, "DOB = date('1974-08-24')");
@@ -424,14 +441,14 @@ DateTime dt = (DateTime) ExpressionEvaluator.GetValue(inventor, "DOB = date('197
Inventor tesla = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers['vp'] = Members[0]");</programlisting></para>
</sect2>
<sect2 id="expressions-explist">
<sect2 xml:id="expressions-explist">
<title>Expression lists</title>
<para>Multiple expressions can be evaluated against the same context
object by separating them with a semicolon and enclosing the entire
expression within parentheses. The value returned is the value of the
last expression in the list. Examples of this are shown below
<programlisting>//Perform property assignments and then return Name property.
<programlisting language="csharp">//Perform property assignments and then return Name property.
String pupin = (String) ExpressionEvaluator.GetValue(ieee.Members,
"( [1].PlaceOfBirth.City = 'Beograd'; [1].PlaceOfBirth.Country = 'Serbia'; [1].Name )"));
@@ -439,11 +456,11 @@ String pupin = (String) ExpressionEvaluator.GetValue(ieee.Members,
// pupin = "Mihajlo Pupin"</programlisting></para>
</sect2>
<sect2 id="expressions-types">
<sect2 xml:id="expressions-types">
<title>Types</title>
<para>In many cases, you can reference types by simply specifying type
name:<programlisting>ExpressionEvaluator.GetValue(null, "1 is int")
name:<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "1 is int")
ExpressionEvaluator.GetValue(null, "DateTime.Today")
@@ -455,7 +472,7 @@ ExpressionEvaluator.GetValue(null, "new string[] {'abc', 'efg'}")</programlistin
next section.</para>
<para>For all other types, you need to use special
<literal>T(typeName)</literal> expression:<programlisting>Type dateType = (Type) ExpressionEvaluator.GetValue(null, "T(System.DateTime)")
<literal>T(typeName)</literal> expression:<programlisting language="csharp">Type dateType = (Type) ExpressionEvaluator.GetValue(null, "T(System.DateTime)")
Type evalType = (Type) ExpressionEvaluator.GetValue(null, "T(Spring.Expressions.ExpressionEvaluator, Spring.Core)")
@@ -463,14 +480,14 @@ bool trueValue = (bool) ExpressionEvaluator.GetValue(tesla, "T(System.DateTime)
<note>
<para>The implementation delegates to Spring's
<classname>ObjectUtils.ResolveType</classname> method for the actual
<literal>ObjectUtils.ResolveType</literal> method for the actual
type resolution, which means that the types used within expressions
are resolved in the exactly the same way as the types specified in
Spring configuration files.</para>
</note>
</sect2>
<sect2 id="expressions-typeregistration">
<sect2 xml:id="expressions-typeregistration">
<title>Type Registration</title>
<para>To refer to a type within an expression that is not in the
@@ -480,7 +497,7 @@ bool trueValue = (bool) ExpressionEvaluator.GetValue(tesla, "T(System.DateTime)
used in expression that use the new operator or refer to a static
properties of an object. Example usage is shown below.</para>
<programlisting>TypeRegistry.RegisterType("Society", typeof(Society));
<programlisting language="csharp">TypeRegistry.RegisterType("Society", typeof(Society));
Inventor pupin = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers[Society.President]");</programlisting>
@@ -488,13 +505,13 @@ Inventor pupin = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers[Society
<literal>typeAliases</literal> configuration section.</para>
</sect2>
<sect2 id="expressions-ctor">
<sect2 xml:id="expressions-ctor">
<title>Constructors</title>
<para>Constructors can be invoked using the new operator. For classes
outside mscorlib you will need to register your types so they can be
resolved. Examples of using constructors are shown below:
<programlisting>// simple ctor
<programlisting language="csharp">// simple ctor
DateTime dt = (DateTime) ExpressionEvaluator.GetValue(null, "new DateTime(1974, 8, 24)");
// Register Inventor type then create new inventor instance within Add method inside an expression list.
@@ -510,7 +527,7 @@ int three = (int) ExpressionEvaluator.GetValue(ieee.Members, "{ Add(new Inventor
instantiation, similar to the way standard .NET attributes work. For
example, you could create an instance of the <literal>Inventor</literal>
class and set its <literal>Inventions</literal> property in a single
statement:<programlisting>
statement:<programlisting language="csharp">
Inventor aleks = (Inventor) ExpressionEvaluator.GetValue(null, "new Inventor('Aleksandar Seovic', date('1974-08-24'), 'Serbian', Inventions = {'SPELL'})");
</programlisting>The only rule you have to follow is that named arguments
should be specified <emphasis>after</emphasis> standard constructor
@@ -520,7 +537,7 @@ Inventor aleks = (Inventor) ExpressionEvaluator.GetValue(null, "new Inventor('Al
provides a convenient syntax for .NET attribute instance creation.
Instead of using standard constructor syntax, you can use a somewhat
shorter and more familiar syntax to create an instance of a .NET
attribute class:<programlisting>
attribute class:<programlisting language="csharp">
WebMethodAttribute webMethod = (WebMethodAttribute) ExpressionEvaluator.GetValue(null, "@[WebMethod(true, CacheDuration = 60, Description = 'My Web Method')]");
</programlisting>As you can see, with the exception of the
<literal>@</literal> prefix, syntax is exactly the same as in C#.</para>
@@ -533,29 +550,29 @@ WebMethodAttribute webMethod = (WebMethodAttribute) ExpressionEvaluator.GetValue
<literal>Attribute</literal> suffix, just like the C# compiler.</para>
</sect2>
<sect2 id="expressions-variables">
<sect2 xml:id="expressions-variables">
<title>Variables</title>
<para>Variables can referenced in the expression using the syntax
<literal>#</literal><emphasis>variableName</emphasis>. The variables are
passed in and out of the expression using the dictionary parameter in
<classname>ExpressionEvaluator</classname>'s <literal>GetValue</literal>
or <literal>SetValue</literal> methods. <programlisting>public static object GetValue(object root, string expression, IDictionary variables)
<literal>ExpressionEvaluator</literal>'s <literal>GetValue</literal>
or <literal>SetValue</literal> methods. <programlisting language="csharp">public static object GetValue(object root, string expression, IDictionary variables)
public static void SetValue(object root, string expression, IDictionary variables, object newValue)</programlisting>
The variable name is the key value of the dictionary. Example usage is
shown below; <programlisting>IDictionary vars = new Hashtable();
shown below; <programlisting language="csharp">IDictionary vars = new Hashtable();
vars["newName"] = "Mike Tesla";
ExpressionEvaluator.GetValue(tesla, "Name = #newName", vars));</programlisting>
You can also use the dictionary as a place to store values of the object
as they are evaluated inside the expression. For example to change
Tesla's first name back again and keep the old value; <programlisting>ExpressionEvaluator.GetValue(tesla, "{ #oldName = Name; Name = 'Nikola Tesla' }", vars);
Tesla's first name back again and keep the old value; <programlisting language="csharp">ExpressionEvaluator.GetValue(tesla, "{ #oldName = Name; Name = 'Nikola Tesla' }", vars);
String oldName = (String)vars["oldName"]; // Mike Tesla</programlisting>
Variable names can also be used inside indexers or maps instead of
literal values. For example; <programlisting>vars["prez"] = "president";
literal values. For example; <programlisting language="csharp">vars["prez"] = "president";
Inventor pupin = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers[#prez]", vars);</programlisting></para>
<sect3 id="expressions-this">
<sect3 xml:id="expressions-this">
<title>The '#this' and '#root' variables</title>
<para>There are two special variables that are always defined and can
@@ -564,24 +581,24 @@ Inventor pupin = (Inventor) ExpressionEvaluator.GetValue(ieee, "Officers[#prez]"
<para>The <literal>#this</literal> variable can be used to explicitly
refer to the context for the node that is currently being
evaluated:<programlisting>// sets the name of the president and returns its instance
evaluated:<programlisting language="csharp">// sets the name of the president and returns its instance
ExpressionEvaluator.GetValue(ieee, "Officers['president'].( #this.Name = 'Nikola Tesla'; #this )")</programlisting></para>
<para>Similarly, the <literal>#root</literal> variable allows you to
refer to the root context for the expression:<programlisting>// removes president from the Officers dictionary and returns removed instance
refer to the root context for the expression:<programlisting language="csharp">// removes president from the Officers dictionary and returns removed instance
ExpressionEvaluator.GetValue(ieee, "Officers['president'].( #root.Officers.Remove('president'); #this )")</programlisting></para>
</sect3>
</sect2>
<sect2 id="expressions-ternary">
<sect2 xml:id="expressions-ternary">
<title>Ternary Operator (If-Then-Else)</title>
<para>You can use the ternary operator for performing if-then-else
conditional logic inside the expression. A minimal example is;
<programlisting>String aTrueString = (String) ExpressionEvaluator.GetValue(null, "false ? 'trueExp' : 'falseExp'") // trueExp
<programlisting language="csharp">String aTrueString = (String) ExpressionEvaluator.GetValue(null, "false ? 'trueExp' : 'falseExp'") // trueExp
</programlisting> In this case, the boolean false results in returning the
string value 'trueExp'. A less artificial example is shown below
<programlisting>ExpressionEvaluator.SetValue(ieee, "Name", "IEEE");
<programlisting language="csharp">ExpressionEvaluator.SetValue(ieee, "Name", "IEEE");
IDictionary vars = new Hashtable();
vars["queryName"] = "Nikola Tesla";
@@ -607,8 +624,8 @@ String queryResultString = (String) ExpressionEvaluator.GetValue(ieee, expressio
<para>For example, let's say that we need a list of the cities where our
inventors were born. This could be easily obtained by projecting on the
<literal>PlaceOfBirth.City</literal> property: <programlisting>IList placesOfBirth = (IList) ExpressionEvaluator.GetValue(ieee, "Members.!{PlaceOfBirth.City}") // { 'Smiljan', 'Idvor' }
</programlisting>Or we can get the list of officers' names:<programlisting>IList officersNames = (IList) ExpressionEvaluator.GetValue(ieee, "Officers.Values.!{Name}") // { 'Nikola Tesla', 'Mihajlo Pupin' }
<literal>PlaceOfBirth.City</literal> property: <programlisting language="csharp">IList placesOfBirth = (IList) ExpressionEvaluator.GetValue(ieee, "Members.!{PlaceOfBirth.City}") // { 'Smiljan', 'Idvor' }
</programlisting>Or we can get the list of officers' names:<programlisting language="csharp">IList officersNames = (IList) ExpressionEvaluator.GetValue(ieee, "Officers.Values.!{Name}") // { 'Nikola Tesla', 'Mihajlo Pupin' }
</programlisting></para>
<para>As you can see from the examples, projection uses
@@ -620,11 +637,11 @@ String queryResultString = (String) ExpressionEvaluator.GetValue(ieee, expressio
<literal>?{</literal><emphasis>projectionExpression</emphasis><literal>}</literal>
syntax, will filter the list and return a new list containing a subset
of the original element list. For example, selection would allow us to
easily get a list of Serbian inventors:<programlisting>IList serbianInventors = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{Nationality == 'Serbian'}") // { tesla, pupin }
easily get a list of Serbian inventors:<programlisting language="csharp">IList serbianInventors = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{Nationality == 'Serbian'}") // { tesla, pupin }
</programlisting>Or to get a list of inventors that invented
sonar:<programlisting>IList sonarInventors = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{'Sonar' in Inventions}") // { pupin }
sonar:<programlisting language="csharp">IList sonarInventors = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{'Sonar' in Inventions}") // { pupin }
</programlisting>Or we can combine selection and projection to get a list of
sonar inventors' names:<programlisting>IList sonarInventorsNames = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{'Sonar' in Inventions}.!{Name}") // { 'Mihajlo Pupin' }
sonar inventors' names:<programlisting language="csharp">IList sonarInventorsNames = (IList) ExpressionEvaluator.GetValue(ieee, "Members.?{'Sonar' in Inventions}.!{Name}") // { 'Mihajlo Pupin' }
</programlisting></para>
<para>As a convenience, Spring.NET Expression Language also supports a
@@ -635,7 +652,7 @@ String queryResultString = (String) ExpressionEvaluator.GetValue(ieee, expressio
elements were found. In order to return a first match you should prefix
your selection expression with <literal>^{</literal> instead of
<literal>?{</literal>, and to return last match you should use
<literal>${</literal> prefix:<programlisting>ExpressionEvaluator.GetValue(ieee, "Members.^{Nationality == 'Serbian'}.Name") // 'Nikola Tesla'
<literal>${</literal> prefix:<programlisting language="csharp">ExpressionEvaluator.GetValue(ieee, "Members.^{Nationality == 'Serbian'}.Name") // 'Nikola Tesla'
ExpressionEvaluator.GetValue(ieee, "Members.${Nationality == 'Serbian'}.Name") // 'Mihajlo Pupin'
</programlisting>Notice that we access the <literal>Name</literal> property
directly on the selection result, because an actual matched instance is
@@ -643,7 +660,7 @@ ExpressionEvaluator.GetValue(ieee, "Members.${Nationality == 'Serbian'}.Name")
list.</para>
</sect2>
<sect2 id="expressions-processors">
<sect2 xml:id="expressions-processors">
<title>Collection Processors and Aggregators</title>
<para>In addition to list projection and selection, Spring.NET
@@ -670,9 +687,9 @@ ExpressionEvaluator.GetValue(ieee, "Members.${Nationality == 'Serbian'}.Name")
<literal>Count</literal> or <literal>Length</literal> property
depending on the context. Unlike its standard .NET counterparts, count
aggregator can also be invoked on the <literal>null</literal> context
without throwing a <classname>NullReferenceException</classname>. It
without throwing a <literal>NullReferenceException</literal>. It
will simply return zero in this case, which makes it much safer than
standard .NET properties within larger expression.<programlisting>ExpressionEvaluator.GetValue(null, "{1, 5, -3}.count()") // 3
standard .NET properties within larger expression.<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "{1, 5, -3}.count()") // 3
ExpressionEvaluator.GetValue(null, "count()") // 0
</programlisting></para>
</sect3>
@@ -685,7 +702,7 @@ ExpressionEvaluator.GetValue(null, "count()") // 0
or precision, it will automatically perform necessary conversion and
the result will be the highest precision type. If any of the
collection elements is not a number, this aggregator will throw an
<classname>InvalidArgumentException</classname>.<programlisting>ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.sum()") // 13 (int)
<literal>InvalidArgumentException</literal>.<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.sum()") // 13 (int)
ExpressionEvaluator.GetValue(null, "{5, 5.8, 12.2, 1}.sum()") // 24.0 (double)
</programlisting></para>
</sect3>
@@ -698,7 +715,7 @@ ExpressionEvaluator.GetValue(null, "{5, 5.8, 12.2, 1}.sum()") // 24.0 (double)
the sum aggregator in order to be as precise as possible. Just like
the sum aggregator, if any of the collection elements is not a number,
it will throw an
<classname>InvalidArgumentException</classname>.<programlisting>ExpressionEvaluator.GetValue(null, "{1, 5, -4, 10}.average()") // 3
<literal>InvalidArgumentException</literal>.<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "{1, 5, -4, 10}.average()") // 3
ExpressionEvaluator.GetValue(null, "{1, 5, -2, 10}.average()") // 3.5
</programlisting></para>
</sect3>
@@ -710,9 +727,9 @@ ExpressionEvaluator.GetValue(null, "{1, 5, -2, 10}.average()") // 3.5
list. In order to determine what "the smallest" actually means, this
aggregator relies on the assumption that the collection items are of
the uniform type and that they implement the
<classname>IComparable</classname> interface. If that is not the case,
<literal>IComparable</literal> interface. If that is not the case,
this aggregator will throw an
<classname>InvalidArgumentException</classname>.<programlisting>ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.min()") // -3
<literal>InvalidArgumentException</literal>.<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.min()") // -3
ExpressionEvaluator.GetValue(null, "{'abc', 'efg', 'xyz'}.min()") // 'abc'
</programlisting></para>
</sect3>
@@ -724,9 +741,9 @@ ExpressionEvaluator.GetValue(null, "{'abc', 'efg', 'xyz'}.min()") // 'abc'
In order to determine what "the largest" actually means, this
aggregator relies on the assumption that the collection items are of
the uniform type and that they implement
<classname>IComparable</classname> interface. If that is not the case,
<literal>IComparable</literal> interface. If that is not the case,
this aggregator will throw an
<classname>InvalidArgumentException</classname>.<programlisting>ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.max()") // 10
<literal>InvalidArgumentException</literal>.<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "{1, 5, -3, 10}.max()") // 10
ExpressionEvaluator.GetValue(null, "{'abc', 'efg', 'xyz'}.max()") // 'xyz'
</programlisting></para>
</sect3>
@@ -736,7 +753,7 @@ ExpressionEvaluator.GetValue(null, "{'abc', 'efg', 'xyz'}.max()") // 'xyz'
<para>A non-null processor is a very simple collection processor that
eliminates all <literal>null</literal> values from the
collection.<programlisting>ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', null, 'abc', 'def', null}.nonNull()") // { 'abc', 'xyz', 'abc', 'def' }
collection.<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', null, 'abc', 'def', null}.nonNull()") // { 'abc', 'xyz', 'abc', 'def' }
ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', null, 'abc', 'def', null}.nonNull().distinct().sort()") // { 'abc', 'def', 'xyz' }
</programlisting></para>
</sect3>
@@ -749,7 +766,7 @@ ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', null, 'abc', 'def', null}.no
an optional <literal>Boolean</literal> argument that will determine
whether <literal>null</literal> values should be included in the
results. The default is <literal>false</literal>, which means that
they will not be included. <programlisting>ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.distinct(true).sort()") // { null, 'abc', 'def', 'xyz' }
they will not be included. <programlisting language="csharp">ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.distinct(true).sort()") // { null, 'abc', 'def', 'xyz' }
ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.distinct(false).sort()") // { 'abc', 'def', 'xyz' }
</programlisting></para>
</sect3>
@@ -758,9 +775,9 @@ ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.
<title>Sort Processor</title>
<para>The sort processor can be used to sort uniform collections of
elements that implement <classname>IComparable</classname>.</para>
elements that implement <literal>IComparable</literal>.</para>
<programlisting>ExpressionEvaluator.GetValue(null, "{1.2, 5.5, -3.3}.sort()") // { -3.3, 1.2, 5.5 }
<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "{1.2, 5.5, -3.3}.sort()") // { -3.3, 1.2, 5.5 }
ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.sort()") // { null, 'abc', 'abc', 'def', 'def', 'xyz' }
</programlisting>
@@ -775,7 +792,7 @@ ExpressionEvaluator.GetValue(null, "{ 'abc', 'xyz', 'abc', 'def', null, 'def' }.
<para>The convert processor can be used to convert a collection of
elements to a given Type.</para>
<programlisting>object[] arr = new object[] { "0", 1, 1.1m, "1.1", 1.1f };
<programlisting language="csharp">object[] arr = new object[] { "0", 1, 1.1m, "1.1", 1.1f };
decimal[] result = (decimal[]) ExpressionEvaluator.GetValue(arr, "convert(decimal)");
</programlisting>
</sect3>
@@ -786,7 +803,7 @@ decimal[] result = (decimal[]) ExpressionEvaluator.GetValue(arr, "convert(decima
<para>The reverse processor returns the reverse order of elements in
the list</para>
<programlisting>object[] arr = new object[] { "0", 1, 2.1m, "3", 4.1f };
<programlisting language="csharp">object[] arr = new object[] { "0", 1, 2.1m, "3", 4.1f };
object[] result = new ArrayList( (ICollection) ExpressionEvaluator.GetValue(arr, "reverse()") ).ToArray(); // { 4.1f, "3", 2.1m, 1, "0" } </programlisting>
</sect3>
@@ -796,13 +813,13 @@ object[] result = new ArrayList( (ICollection) ExpressionEvaluator.GetValue(arr,
<para>Collections can be ordered in three ways, an expression, a SpEL
lamda expreression, or a delegate.</para>
<programlisting><emphasis role="bold">// orderBy expression</emphasis>
<programlisting language="csharp">// orderBy expression
IExpression exp = Expression.Parse("orderBy('ToString()')");
object[] input = new object[] { 'b', 1, 2.0, "a" };
object[] ordered = exp.GetValue(input); // { 1, 2.0, "a", 'b' }
<emphasis role="bold">// SpEL lambda expressions</emphasis>
// SpEL lambda expressions
IExpression exp = Expression.Parse("orderBy({|a,b| $a.ToString().CompareTo($b.ToString())})");
object[] input = new object[] { 'b', 1, 2.0, "a" };
object[] ordered = exp.GetValue(input); // { 1, 2.0, "a", 'b' }
@@ -812,7 +829,7 @@ Expression.RegisterFunction( "compare", "{|a,b| $a.ToString().CompareTo($b.ToStr
exp = Expression.Parse("orderBy(#compare)");
ordered = exp.GetValue(input, vars); // { 1, 2.0, "a", 'b' }
<emphasis role="bold">// .NET delegate</emphasis>
// .NET delegate
private delegate int CompareCallback(object x, object y);
private int CompareObjects(object x, object y)
{
@@ -837,7 +854,7 @@ object[] ordered = exp.GetValue(input); // { 1, 2.0, "a", 'b' }
implementation that sums only the even numbers of an integer
list</para>
<programlisting> public class IntEvenSumCollectionProcessor : ICollectionProcessor
<programlisting language="csharp"> public class IntEvenSumCollectionProcessor : ICollectionProcessor
{
public object Process(ICollection source, object[] args)
{
@@ -874,7 +891,7 @@ object[] ordered = exp.GetValue(input); // { 1, 2.0, "a", 'b' }
</sect3>
</sect2>
<sect2 id="expressions-object-references">
<sect2 xml:id="expressions-object-references">
<title>Spring Object References</title>
<para>Expressions can refer to objects that are declared in Spring's
@@ -884,7 +901,7 @@ object[] ordered = exp.GetValue(input); // { 1, 2.0, "a", 'b' }
(<literal>Spring.RootContext</literal>) is used. Using the application
context defined in the MovieFinder example from <xref
linkend="quickstarts" />, the following expression returns the number of
movies directed by Roberto Benigni. <programlisting>public static void Main()
movies directed by Roberto Benigni. <programlisting language="csharp">public static void Main()
{
. . .
@@ -900,7 +917,7 @@ int numMovies = (int) ExpressionEvaluator.GetValue(null,
example.</para>
</sect2>
<sect2 id="expressions-lamda">
<sect2 xml:id="expressions-lamda">
<title>Lambda Expressions</title>
<para>A somewhat advanced, but a very powerful feature of Spring.NET
@@ -916,7 +933,7 @@ int numMovies = (int) ExpressionEvaluator.GetValue(null,
</literal><emphasis>functionBody</emphasis><literal> }</literal></para>
<para>For example, you could define a <literal>max</literal> function
and call it like this:<programlisting>ExpressionEvaluator.GetValue(null, "(#max = {|x,y| $x &gt; $y ? $x : $y }; #max(5,25))", new Hashtable()) // 25</programlisting></para>
and call it like this:<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "(#max = {|x,y| $x &gt; $y ? $x : $y }; #max(5,25))", new Hashtable()) // 25</programlisting></para>
<para>As you can see, any arguments defined for the expression can be
referenced within the function body using a <emphasis>local
@@ -927,7 +944,7 @@ int numMovies = (int) ExpressionEvaluator.GetValue(null,
function name.</para>
<para>Lambda expressions can be recursive, which means that you can
invoke the function within its own body:<programlisting>ExpressionEvaluator.GetValue(null, "(#fact = {|n| $n &lt;= 1 ? 1 : $n * #fact($n-1) }; #fact(5))", new Hashtable()) // 120</programlisting></para>
invoke the function within its own body:<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "(#fact = {|n| $n &lt;= 1 ? 1 : $n * #fact($n-1) }; #fact(5))", new Hashtable()) // 120</programlisting></para>
<para>Notice that in both examples above we had to specify a
<literal>variables</literal> parameter for the
@@ -945,13 +962,13 @@ int numMovies = (int) ExpressionEvaluator.GetValue(null,
easy way to pre-register your lambda expressions by exposing a static
<literal>Expression.RegisterFunction</literal> method, which takes
function name, lambda expression and variables dictionary to register
function in as parameters:<programlisting>IDictionary vars = new Hashtable();
function in as parameters:<programlisting language="csharp">IDictionary vars = new Hashtable();
Expression.RegisterFunction("sqrt", "{|n| Math.Sqrt($n)}", vars);
Expression.RegisterFunction("fact", "{|n| $n &lt;= 1 ? 1 : $n * #fact($n-1)}", vars);</programlisting>Once
the function registration is done, you can simply evaluate an expression
that uses these functions, making sure that the <literal>vars</literal>
dictionary is passed as a parameter to expression evaluation
engine:<programlisting>ExpressionEvaluator.GetValue(null, "#fact(5)", vars) // 120
engine:<programlisting language="csharp">ExpressionEvaluator.GetValue(null, "#fact(5)", vars) // 120
ExpressionEvaluator.GetValue(null, "#sqrt(9)", vars) // 3</programlisting></para>
<para>Finally, because lambda expressions are treated as variables, they
@@ -961,7 +978,7 @@ ExpressionEvaluator.GetValue(null, "#sqrt(9)", vars) // 3</programlisting></par
argument and parameter <literal>n</literal> that will be passed to
function <literal>f</literal> as the second. Then we invoke the
functions registered in the previous example, as well as the lambda
expression defined inline, through our delegate:<programlisting>Expression.RegisterFunction("delegate", "{|f, n| $f($n) }", vars);
expression defined inline, through our delegate:<programlisting language="csharp">Expression.RegisterFunction("delegate", "{|f, n| $f($n) }", vars);
ExpressionEvaluator.GetValue(null, "#delegate(#sqrt, 4)", vars) // 2
ExpressionEvaluator.GetValue(null, "#delegate(#fact, 5)", vars) // 120
ExpressionEvaluator.GetValue(null, "#delegate({|n| $n ^ 2 }, 5)", vars) // 25</programlisting>While
@@ -980,7 +997,7 @@ ExpressionEvaluator.GetValue(null, "#delegate({|n| $n ^ 2 }, 5)", vars) // 25</
<para>For example, you can define a max delegate and call it like
this</para>
<programlisting>private delegate double DoubleFunctionTwoArgs(double arg1, double arg2);
<programlisting language="csharp">private delegate double DoubleFunctionTwoArgs(double arg1, double arg2);
private double Max(double arg1, double arg2)
{
@@ -1013,13 +1030,13 @@ public void DoWork()
<!-- SAMPLE CLASSES AND DATA -->
<sect1 id="expressions-classes">
<sect1 xml:id="expressions-classes">
<title>Classes used in the examples</title>
<para>The following simple classes are used to demonstrate the
functionality of the expression language.</para>
<programlisting>public class Inventor
<programlisting language="csharp">public class Inventor
{
public string Name;
public string Nationality;
@@ -1099,7 +1116,7 @@ public class Society
<para>The code listings in this chapter use instances of the data
populated with the following information.</para>
<programlisting>Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian");
<programlisting language="csharp">Inventor tesla = new Inventor("Nikola Tesla", new DateTime(1856, 7, 9), "Serbian");
tesla.Inventions = new string[]
{
"Telephone repeater", "Rotating magnetic field principle",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -1,63 +1,63 @@
<?xml version='1.0' encoding="iso-8859-1"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"../../reference/lib/docbook-dtd/docbookx.dtd"
[
<!ENTITY aop SYSTEM "aop.xml">
<!ENTITY aop-aspect-library SYSTEM "aop-aspect-library.xml">
<!ENTITY background SYSTEM "background.xml">
<!ENTITY objects SYSTEM "objects.xml">
<!ENTITY resources SYSTEM "resources.xml">
<!ENTITY objects-misc SYSTEM "objects-misc.xml">
<!ENTITY expressions SYSTEM "expressions.xml">
<!ENTITY validation SYSTEM "validation.xml">
<!ENTITY logging SYSTEM "logging.xml">
<!ENTITY testing SYSTEM "testing.xml">
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE book [
<!ENTITY aop SYSTEM "aop.xml">
<!ENTITY aop-aspect-library SYSTEM "aop-aspect-library.xml">
<!ENTITY background SYSTEM "background.xml">
<!ENTITY objects SYSTEM "objects.xml">
<!ENTITY resources SYSTEM "resources.xml">
<!ENTITY objects-misc SYSTEM "objects-misc.xml">
<!ENTITY expressions SYSTEM "expressions.xml">
<!ENTITY validation SYSTEM "validation.xml">
<!ENTITY logging SYSTEM "logging.xml">
<!ENTITY testing SYSTEM "testing.xml">
<!ENTITY overview SYSTEM "overview.xml">
<!ENTITY psa-intro SYSTEM "psa-intro.xml">
<!ENTITY remoting SYSTEM "remoting.xml">
<!ENTITY messaging SYSTEM "messaging.xml">
<!ENTITY msmq SYSTEM "msmq.xml">
<!ENTITY scheduling SYSTEM "scheduling.xml">
<!ENTITY web SYSTEM "web.xml">
<!ENTITY ajax SYSTEM "ajax.xml">
<!ENTITY services SYSTEM "services.xml">
<!ENTITY webservices SYSTEM "webservices.xml">
<!ENTITY wcf SYSTEM "wcf.xml">
<!ENTITY threading SYSTEM "threading.xml">
<!ENTITY pool SYSTEM "pool.xml">
<!ENTITY preface SYSTEM "preface.xml">
<!ENTITY transaction SYSTEM "transaction.xml">
<!ENTITY dbprovider SYSTEM "dbprovider.xml">
<!ENTITY dao SYSTEM "dao.xml">
<!ENTITY ado SYSTEM "ado.xml">
<!ENTITY orm SYSTEM "orm.xml">
<!ENTITY vsnet SYSTEM "vsnet.xml">
<!ENTITY migration SYSTEM "migration.xml">
<!ENTITY quickstarts SYSTEM "quickstarts.xml">
<!ENTITY aop-quickstart SYSTEM "aop-quickstart.xml">
<!ENTITY remoting-quickstart SYSTEM "remoting-quickstart.xml">
<!ENTITY springair SYSTEM "springair.xml">
<!ENTITY web-quickstart SYSTEM "web-quickstart.xml">
<!ENTITY data-quickstart SYSTEM "data-quickstart.xml">
<!ENTITY tx-quickstart SYSTEM "tx-quickstart.xml">
<!ENTITY quartz-quickstart SYSTEM "quartz-quickstart.xml">
<!ENTITY nms-quickstart SYSTEM "nms-quickstart.xml">
<!ENTITY msmq-quickstart SYSTEM "msmq-quickstart.xml">
<!ENTITY wcf-quickstart SYSTEM "wcf-quickstart.xml">
<!ENTITY javadevelopers SYSTEM "javadevelopers.xml">
<!ENTITY misc SYSTEM "misc.xml">
<!ENTITY pooling-example SYSTEM "pooling-example.xml">
<!ENTITY xsd-configuration SYSTEM "xsd-configuration.xml">
<!ENTITY xml-custom SYSTEM "xml-custom.xml">
<!ENTITY xsd SYSTEM "xsd.xml">
<!ENTITY overview SYSTEM "overview.xml">
<!ENTITY psa-intro SYSTEM "psa-intro.xml">
<!ENTITY remoting SYSTEM "remoting.xml">
<!ENTITY messaging SYSTEM "messaging.xml">
<!ENTITY msmq SYSTEM "msmq.xml">
<!ENTITY scheduling SYSTEM "scheduling.xml">
<!ENTITY web SYSTEM "web.xml">
<!ENTITY ajax SYSTEM "ajax.xml">
<!ENTITY services SYSTEM "services.xml">
<!ENTITY webservices SYSTEM "webservices.xml">
<!ENTITY wcf SYSTEM "wcf.xml">
<!ENTITY threading SYSTEM "threading.xml">
<!ENTITY pool SYSTEM "pool.xml">
<!ENTITY preface SYSTEM "preface.xml">
<!ENTITY transaction SYSTEM "transaction.xml">
<!ENTITY dbprovider SYSTEM "dbprovider.xml">
<!ENTITY dao SYSTEM "dao.xml">
<!ENTITY ado SYSTEM "ado.xml">
<!ENTITY orm SYSTEM "orm.xml">
<!ENTITY vsnet SYSTEM "vsnet.xml">
<!ENTITY migration SYSTEM "migration.xml">
<!ENTITY quickstarts SYSTEM "quickstarts.xml">
<!ENTITY aop-quickstart SYSTEM "aop-quickstart.xml">
<!ENTITY remoting-quickstart SYSTEM "remoting-quickstart.xml">
<!ENTITY springair SYSTEM "springair.xml">
<!ENTITY web-quickstart SYSTEM "web-quickstart.xml">
<!ENTITY data-quickstart SYSTEM "data-quickstart.xml">
<!ENTITY tx-quickstart SYSTEM "tx-quickstart.xml">
<!ENTITY quartz-quickstart SYSTEM "quartz-quickstart.xml">
<!ENTITY nms-quickstart SYSTEM "nms-quickstart.xml">
<!--<!ENTITY msmq-quickstart SYSTEM "msmq-quickstart.xml">-->
<!ENTITY wcf-quickstart SYSTEM "wcf-quickstart.xml">
<!ENTITY javadevelopers SYSTEM "javadevelopers.xml">
<!ENTITY misc SYSTEM "misc.xml">
<!ENTITY pooling-example SYSTEM "pooling-example.xml">
<!ENTITY xsd-configuration SYSTEM "xsd-configuration.xml">
<!ENTITY xml-custom SYSTEM "xml-custom.xml">
<!ENTITY xsd SYSTEM "xsd.xml">
]>
<book>
<bookinfo>
<book xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://docbook.org/ns/docbook/xi"
version="5.0"
xml:lang="en">
<info>
<title>The Spring.NET Framework</title>
<subtitle>Reference Documentation</subtitle>
<releaseinfo>Version 1.2.0 M1</releaseinfo>
@@ -81,7 +81,7 @@
</author>
<author>
<firstname>Federico</firstname>
<surname>Spinazzi</surname>
<surname>Spinazzi</surname>
</author>
<author>
<firstname>Rob</firstname>
@@ -110,328 +110,318 @@
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>
</para>
</legalnotice>
</bookinfo>
</info>
<toc/>
&preface;
&overview;
&background;
&migration;
<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 enterprise programming.
</para>
<para>
The core functionality also includes an expression language
for lightweight scripting and a ui-agnostic validation framework.
</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 properties 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>
<xref linkend="objects" />
</listitem>
<listitem>
<xref linkend="objects-misc" />
</listitem>
<listitem>
<xref linkend="resources" />
</listitem>
<listitem>
<xref linkend="threading" />
</listitem>
<listitem>
<xref linkend="pool" />
</listitem>
<listitem>
<xref linkend="expressions" />
</listitem>
<listitem>
<xref linkend="misc" />
</listitem>
<listitem>
<xref linkend="validation" />
</listitem>
<listitem>
<xref linkend="aop" />
</listitem>
<listitem>
<xref linkend="aop-aspect-library" />
</listitem>
<listitem>
<xref linkend="logging" />
</listitem>
<listitem>
<xref linkend="testing" />
</listitem>
</itemizedlist>
</partintro>
&objects;
&objects-misc;
&resources;
&threading;
&pool;
&misc;
&expressions;
&validation;
<!-- &util; -->
&aop;
&aop-aspect-library;
&logging;
&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 othe 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>
<xref linkend="transaction" />
</listitem>
<listitem>
<xref linkend="dao" />
</listitem>
<listitem>
<xref linkend="dbprovider" />
</listitem>
<listitem>
<xref linkend="ado" />
</listitem>
<listitem>
<xref linkend="orm" />
</listitem>
</itemizedlist>
</partintro>
&transaction;
&dao;
&dbprovider;
&ado;
&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,
specifically web-based presentation tiers.
</para>
<itemizedlist>
<listitem>
<xref linkend="web" />
</listitem>
<listitem>
<xref linkend="ajax" />
</listitem>
</itemizedlist>
</partintro>
&web;
&ajax;
</part>
<part id="index-services">
<title>Services</title>
<partintro>
<para>
This part of the reference documentation covers
the Spring Framework's integration with .NET distributed
technologies such as .NET Remoting, Enterprise Services,
Web Services. Integration with WCF Services is forthcoming.
Please refer to the introduction chapter for more details.
</para>
<itemizedlist>
<listitem>
<xref linkend="psa-intro" />
</listitem>
<listitem>
<xref linkend="remoting" />
</listitem>
<listitem>
<xref linkend="services" />
</listitem>
<listitem>
<xref linkend="webservices" />
</listitem>
<listitem>
<xref linkend="wcf" />
</listitem>
</itemizedlist>
</partintro>
&psa-intro;
&remoting;
&services;
&webservices;
&wcf;
</part>
&preface;
&overview;
&background;
&migration;
<part xml:id="spring-core">
<title>Core Technologies</title>
<partintro>
<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 enterprise programming.
</para>
<para>
The core functionality also includes an expression language
for lightweight scripting and a ui-agnostic validation framework.
</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 properties 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>
<xref linkend="objects" />
</listitem>
<listitem>
<xref linkend="objects-misc" />
</listitem>
<listitem>
<xref linkend="resources" />
</listitem>
<listitem>
<xref linkend="threading" />
</listitem>
<listitem>
<xref linkend="pool" />
</listitem>
<listitem>
<xref linkend="expressions" />
</listitem>
<listitem>
<xref linkend="misc" />
</listitem>
<listitem>
<xref linkend="validation" />
</listitem>
<listitem>
<xref linkend="aop" />
</listitem>
<listitem>
<xref linkend="aop-aspect-library" />
</listitem>
<listitem>
<xref linkend="logging" />
</listitem>
<listitem>
<xref linkend="testing" />
</listitem>
</itemizedlist>
</partintro>
&objects;
&objects-misc;
&resources;
&threading;
&pool;
&misc;
&expressions;
&validation;
<!-- &util; -->
&aop;
&aop-aspect-library;
&logging;
&testing;
</part>
<part xml:id="spring-middle-tier">
<title>Middle Tier Data Access</title>
<partintro>
<para>
This part of the reference documentation is concerned
with othe 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>
<xref linkend="transaction" />
</listitem>
<listitem>
<xref linkend="dao" />
</listitem>
<listitem>
<xref linkend="dbprovider" />
</listitem>
<listitem>
<xref linkend="ado" />
</listitem>
<listitem>
<xref linkend="orm" />
</listitem>
</itemizedlist>
</partintro>
&transaction;
&dao;
&dbprovider;
&ado;
&orm;
</part>
<part xml:id="spring-web">
<title>The Web</title>
<partintro>
<para>
This part of the reference documentation covers the
Spring Framework's support for the presentation tier,
specifically web-based presentation tiers.
</para>
<itemizedlist>
<listitem>
<xref linkend="web" />
</listitem>
<listitem>
<xref linkend="ajax" />
</listitem>
</itemizedlist>
</partintro>
&web;
&ajax;
</part>
<part xml:id="spring-services">
<title>Services</title>
<partintro>
<para>
This part of the reference documentation covers
the Spring Framework's integration with .NET distributed
technologies such as .NET Remoting, Enterprise Services,
Web Services. Integration with WCF Services is forthcoming.
Please refer to the introduction chapter for more details.
</para>
<itemizedlist>
<listitem>
<xref linkend="psa-intro" />
</listitem>
<listitem>
<xref linkend="remoting" />
</listitem>
<listitem>
<xref linkend="services" />
</listitem>
<listitem>
<xref linkend="webservices" />
</listitem>
<listitem>
<xref linkend="wcf" />
</listitem>
</itemizedlist>
</partintro>
&psa-intro;
&remoting;
&services;
&webservices;
&wcf;
</part>
<part xml:id="spring-integration">
<title>Integration</title>
<partintro>
<para>
This part of the reference documentation covers
the Spring Framework's integration with a number of
related enterprise .NET technologies.
</para>
<itemizedlist>
<listitem>
<para>
<xref linkend="messaging"/>
</para>
</listitem>
<listitem>
<para>
<xref linkend="msmq"/>
</para>
</listitem>
<listitem>
<para>
<xref linkend="scheduling"/>
</para>
</listitem>
</itemizedlist>
</partintro>
&messaging;
&msmq;
&scheduling;
</part>
<part xml:id="spring-vsnet">
<title>VS.NET Integration</title>
<partintro>
<para>
This part of the reference documentation covers
the Spring Framework's integration with VS.NET
</para>
<itemizedlist>
<listitem>
<xref linkend="vsnet" />
</listitem>
</itemizedlist>
</partintro>
&vsnet;
</part>
<part xml:id="spring-quickstarts">
<title>Quickstart applications</title>
<partintro>
<para>
This part of the reference documentation covers
the quickstart applications included with
Spring that demonstrate features in a code centric
manner.
</para>
<itemizedlist>
<listitem>
<xref linkend="quickstarts" />
</listitem>
<listitem>
<xref linkend="aop-quickstart" />
</listitem>
<listitem>
<xref linkend="remoting-quickstart" />
</listitem>
<listitem>
<xref linkend="web-quickstart" />
</listitem>
<listitem>
<xref linkend="springair" />
</listitem>
<listitem>
<xref linkend="data-quickstart" />
</listitem>
<listitem>
<xref linkend="tx-quickstart" />
</listitem>
<listitem>
<xref linkend="quartz-quickstart" />
</listitem>
<listitem>
<xref linkend="nms-quickstart" />
</listitem>
<!--<listitem>
<xref linkend="msmq-quickstart" />
</listitem>-->
<listitem>
<xref linkend="wcf-quickstart" />
</listitem>
</itemizedlist>
</partintro>
&quickstarts;
&aop-quickstart;
&remoting-quickstart;
&web-quickstart;
&springair;
&data-quickstart;
&tx-quickstart;
&quartz-quickstart;
&nms-quickstart;
<!--&msmq-quickstart;-->
&wcf-quickstart;
</part>
<part xml:id="spring-javadevelopers">
<title>Spring.NET for Java developers</title>
<partintro>
<para>
This part of the reference documentation
is for Java developers who would like a quick
orientation to what is different between
the Java and .NET versions of the framework.
</para>
<itemizedlist>
<listitem>
<xref linkend="javadevelopers" />
</listitem>
</itemizedlist>
</partintro>
&javadevelopers;
</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
related enterprise .NET technologies.
</para>
<itemizedlist>
<listitem>
<para><xref linkend="messaging"/></para>
</listitem>
<listitem>
<para><xref linkend="msmq"/></para>
</listitem>
<listitem>
<para><xref linkend="scheduling"/></para>
</listitem>
</itemizedlist>
</partintro>
&messaging;
&msmq;
&scheduling;
</part>
<part id="index-vsnet">
<title>VS.NET Integration</title>
<partintro>
<para>
This part of the reference documentation covers
the Spring Framework's integration with VS.NET
</para>
<itemizedlist>
<listitem>
<xref linkend="vsnet" />
</listitem>
</itemizedlist>
</partintro>
&vsnet;
</part>
<part id="index-quickstarts">
<title>Quickstart applications</title>
<partintro>
<para>
This part of the reference documentation covers
the quickstart applications included with
Spring that demonstrate features in a code centric
manner.
</para>
<itemizedlist>
<listitem>
<xref linkend="quickstarts" />
</listitem>
<listitem>
<xref linkend="aop-quickstart" />
</listitem>
<listitem>
<xref linkend="remoting-quickstart" />
</listitem>
<listitem>
<xref linkend="web-quickstart" />
</listitem>
<listitem>
<xref linkend="springair" />
</listitem>
<listitem>
<xref linkend="data-quickstart" />
</listitem>
<listitem>
<xref linkend="tx-quickstart" />
</listitem>
<listitem>
<xref linkend="quartz-quickstart" />
</listitem>
<listitem>
<xref linkend="nms-quickstart" />
</listitem>
<listitem>
<xref linkend="msmq-quickstart" />
</listitem>
<listitem>
<xref linkend="wcf-quickstart" />
</listitem>
</itemizedlist>
</partintro>
&quickstarts;
&aop-quickstart;
&remoting-quickstart;
&web-quickstart;
&springair;
&data-quickstart;
&tx-quickstart;
&quartz-quickstart;
&nms-quickstart;
&msmq-quickstart;
&wcf-quickstart;
</part>
<part id="index-javadevelopers">
<title>Spring.NET for Java developers</title>
<partintro>
<para>
This part of the reference documentation
is for Java developers who would like a quick
orientation to what is different between
the Java and .NET versions of the framework.
</para>
<itemizedlist>
<listitem>
<xref linkend="javadevelopers" />
</listitem>
</itemizedlist>
</partintro>
&javadevelopers;
</part>
<!-- back matter -->
&xsd-configuration;
&xml-custom;
&xsd;
<!-- back matter -->
&xsd-configuration;
&xml-custom;
&xsd;
</book>

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="javadevelopers">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="javadevelopers" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Spring.NET for Java Developers</title>
<sect1 id="jd-introduction">
<sect1 xml:id="jd-introduction">
<title>Introduction</title>
<para>This chapter is to help Java developers get their sea legs using
@@ -11,21 +28,21 @@
experience when you start to use Spring.NET.</para>
</sect1>
<sect1 id="jd-beans-objects">
<sect1 xml:id="jd-beans-objects">
<title>Beans to Objects</title>
<para>There are some simple name changes, basically everywhere you saw the
word 'bean' you will now see the word 'object'. A comparison of a simple
Spring configuration file highlights these small name changes. Here is the
application.xml file for the sample MovieFinder application in Spring.Java
<programlisting>&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"&gt;
<programlisting language="myxml">&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"&gt;
&lt;beans&gt;
&lt;bean id="MyMovieLister" class="MovieFinder.MovieLister"&gt;
&lt;property name="finder" ref="MyMovieFinder"/&gt;
&lt;/bean&gt;
&lt;bean id="MyMovieFinder" class="MovieFinder.SimpleMovieFinder"/&gt;
&lt;/beans&gt;</programlisting> Here is the corresponding file in Spring.NET
<programlisting>&lt;objects xmlns="http://www.springframework.net"
<programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects-1.1.xsd"&gt;
&lt;object name="MyMovieLister"
@@ -46,9 +63,8 @@
<para>The other XML Schema elements in Spring.NET are the same as in
Spring.Java's DTD except for specifying string based key value pairs. In
Java this is represented by the java.util.Properties class and the xml
element is name &lt;props&gt; as shown below <programlisting
format="linespecific" xml:space="preserve">
&lt;property name="people"&gt;
element is name &lt;props&gt; as shown below
<programlisting language="xml">&lt;property name="people"&gt;
&lt;props&gt;
&lt;prop key="PennAndTeller"&gt;The magic property&lt;/prop&gt;
&lt;prop key="GeorgeCarlin"&gt;The funny property&lt;/prop&gt;
@@ -58,8 +74,7 @@
the xml element &lt;name-values&gt;. The listing of the elements also
follows the .NET convention of application configuration files using the
&lt;add&gt; element with 'key' and 'value' attributes. This is show below
<programlisting format="linespecific" xml:space="preserve">
&lt;property name="people"&gt;
<programlisting language="xml">&lt;property name="people"&gt;
&lt;name-values&gt;
&lt;add key="PennAndTeller" value="The magic property"/&gt;
&lt;add key="GeorgeCarlin" value="The funny property"/&gt;
@@ -67,7 +82,7 @@
&lt;/property&gt;</programlisting></para>
</sect1>
<sect1 id="jd-propertyeditor-typeconverter">
<sect1 xml:id="jd-propertyeditor-typeconverter">
<title>PropertyEditors to TypeConverters</title>
<para>PropertyEditors from the java.beans package provide the ability to
@@ -90,11 +105,11 @@
approach.</para>
</sect1>
<sect1 id="jd-ResourceBundle-ResourceManager">
<sect1 xml:id="jd-ResourceBundle-ResourceManager">
<title>ResourceBundle-ResourceManager</title>
</sect1>
<sect1 id="jd-exceptions">
<sect1 xml:id="jd-exceptions">
<title>Exceptions</title>
<para>Exceptions in Java can either be checked or unchecked. .NET supports
@@ -104,7 +119,7 @@
of .NET</para>
</sect1>
<sect1 id="jd-app-config">
<sect1 xml:id="jd-app-config">
<title>Application Configuration</title>
<para>In Spring.Java it is very common to create an ObjectFactory or
@@ -135,7 +150,7 @@
without coding or using more verbose XML as would be required in the
current version of Spring.Java</para>
<programlisting>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
<programlisting language="myxml">&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;configuration&gt;
&lt;configSections&gt;
@@ -177,35 +192,35 @@
<para>The following code segment is used to retrieve the
IApplicationContext from the .NET application configuration file.
<programlisting>IApplicationContext ctx
<programlisting language="csharp">IApplicationContext ctx
= ConfigurationUtils.GetSection("spring/context") as IApplicationContext;</programlisting></para>
<para>In order to enforce the usage of the named configuration section
<literal>spring/context</literal> the preferred instantiation mechanism is
via the use of the registry class ContextRegistry as shown below
<programlisting>IApplicationContext ctx = ContextRegistry.GetContext();</programlisting></para>
<programlisting language="csharp">IApplicationContext ctx = ContextRegistry.GetContext();</programlisting></para>
</sect1>
<sect1 id="jd-aop-framework">
<sect1 xml:id="jd-aop-framework">
<title>AOP Framework</title>
<sect2 id="NoTargetInInterceptorNames">
<sect2 xml:id="NoTargetInInterceptorNames">
<title>Cannot specify target name at the end of interceptorNames for
ProxyFactoryObject</title>
<para>When configuring the list of interceptor names on a
<classname>ProxyFactoryObject</classname> instance (or object
<literal>ProxyFactoryObject</literal> instance (or object
definition), one <emphasis>cannot</emphasis> specify the name of the
target (i.e. the object being proxied) at the end of the list of
interceptor names. This shortcut <emphasis>is</emphasis> valid in Spring
Java, where the <classname>ProxyFactoryBean</classname> will
Java, where the <literal>ProxyFactoryBean</literal> will
automatically detect this, and use the last name in the interceptor
names list as the target of the <classname>ProxyFactoryBean</classname>.
names list as the target of the <literal>ProxyFactoryBean</literal>.
The following configuration, which would be valid in Spring Java
(barring the obvious element name changes), is <emphasis
role="bold">not</emphasis> valid in Spring.NET (so don't do it).</para>
<programlisting>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
<programlisting language="myxml">&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;objects xmlns="http://www.springframework.net"&gt;
&lt;object id="target" type="Spring.Objects.TestObject"&gt;
&lt;property name="name" value="Bingo"/&gt;
@@ -219,7 +234,7 @@
&lt;/objects&gt;</programlisting>
<para>In Spring.NET, the <literal>InterceptorNames</literal> property of
the <classname>ProxyFactoryObject</classname> can
the <literal>ProxyFactoryObject</literal> can
<emphasis>only</emphasis> be used to specify the names of interceptors.
Use the <literal>TargetName</literal> property to specify the name of
the target object that is to be proxied.</para>

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="logging">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="logging" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Common Logging</title>
<section id="logging-abstract">
<section xml:id="logging-abstract">
<title>Introduction</title>
<para>Spring uses a simple logging abstraction in order to provide a layer

View File

@@ -1,5 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="messaging">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="messaging" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Message Oriented Middleware</title>
<section>
@@ -61,7 +78,7 @@
<literal>NmsTemplate</literal>, <literal> EmsTemplate</literal> (etc.) is
used. Asynchronous message consumption is performed though a
multi-threaded message listener container,
<classname>SimpleMessageListenerContainer</classname>. This message
<literal>SimpleMessageListenerContainer</literal>. This message
listener container is used to create Message-Driven PONOs (MDPs) which
refer to a messaging callback class that consists of just 'plain .NET
object's and is devoid of any specific messaging types or other artifacts.
@@ -73,7 +90,7 @@
<literal>Spring.Messaging.&lt;Vendor&gt;.Core</literal> contains the
messing template class (e.g. <literal>NmsTemplate</literal>). The template
class simplifies the use of the messaging APIs by handling the creation
and release of resources, much like the <classname>AdoTemplate</classname>
and release of resources, much like the <literal>AdoTemplate</literal>
does for ADO.NET. The JMS inspired APIs are low-level API, much like
ADO.NET. As such, even the simplest of operations requires 10s of lines of
code with the bulk of that code related to resource management of
@@ -205,35 +222,35 @@
<title>Messaging Template overview</title>
<para>Code that uses the messaging template classes
(<classname>NmsTemplate</classname>, <classname>EmsTemplate</classname>,
(<literal>NmsTemplate</literal>, <literal>EmsTemplate</literal>,
etc) only needs to implement callback interfaces giving them a clearly
defined contract. The <classname>IMessageCreator</classname> callback
defined contract. The <literal>IMessageCreator</literal> callback
interface creates a message given a Session provided by the calling code
in <literal>NmsTemplate</literal>. In order to allow for more complex
usage of the provider messaging API, the callback
<classname>ISessionCallback</classname> provides the user with the
<literal>ISessionCallback</literal> provides the user with the
provider specific messaging Session and the callback
<classname>IProducerCallback</classname> exposes a provider specific
<literal>IProducerCallback</literal> exposes a provider specific
Session and MessageProducer pair.</para>
<para>Provider messaging APIs typically expose two types of send
methods, one that takes delivery mode, priority, and time-to-live as
quality of service (QOS) parameters and one that takes no QOS parameters
which uses default values. Since there are many higher level send
methods in <classname>NmsTemplate</classname>, the setting of the QOS
methods in <literal>NmsTemplate</literal>, the setting of the QOS
parameters have been exposed as properties on the template class to
avoid duplication in the number of send methods. Similarly, the timeout
value for synchronous receive calls is set using the property
<classname>ReceiveTimeout</classname>.</para>
<literal>ReceiveTimeout</literal>.</para>
<note>
<para>Instances of the <literal>NmsTemplate</literal> class are
thread-safe once configured. This is important because it means that
you can configure a single instance of a
<classname>NmsTemplate</classname> and then safely inject this shared
<literal>NmsTemplate</literal> and then safely inject this shared
reference into multiple collaborators. To be clear, the
<classname>NmsTemplate</classname> is stateful, in that it maintains a
reference to a <classname>ConnectionFactory</classname>, but this
<literal>NmsTemplate</literal> is stateful, in that it maintains a
reference to a <literal>ConnectionFactory</literal>, but this
state is not conversational state.</para>
</note>
</section>
@@ -241,7 +258,7 @@
<section>
<title>Connections</title>
<para>The <classname>NmsTemplate</classname> requires a reference to a
<para>The <literal>NmsTemplate</literal> requires a reference to a
ConnectionFactory. The ConnectionFactory serves as the entry point for
working with the provider's messaging API. It is used by the client
application as a factory to create connections to the messaging server
@@ -268,7 +285,7 @@
creating many intermediate objects. To send a message the following
'API' walk is performed</para>
<programlisting>IConnectionFactory-&gt;IConnection-&gt;ISession-&gt;IMessageProducer-&gt;Send</programlisting>
<programlisting language="csharp">IConnectionFactory-&gt;IConnection-&gt;ISession-&gt;IMessageProducer-&gt;Send</programlisting>
<para>Between the ConnectionFactory and the Send operation there are
three intermediate objects that are created and destroyed. To optimise
@@ -280,15 +297,15 @@
<section>
<title>SingleConnectionFactory</title>
<para><classname>Spring.Messaging.Nms.Connections.SingleConnectionFactory
</classname>will return the same connection on all calls to
<para><literal>Spring.Messaging.Nms.Connections.SingleConnectionFactory
</literal>will return the same connection on all calls to
CreateConnection and ignore calls to Close.</para>
</section>
<section>
<title>CachingConnectionFactory</title>
<para><classname>Spring.Messaging.Nms.Connections.CachingConnectionFactory</classname>
<para><literal>Spring.Messaging.Nms.Connections.CachingConnectionFactory</literal>
extends the functionality of SingleConnectionFactory and adds the
caching of Sessions, MessageProducers, and MessageConsumers.</para>
@@ -298,14 +315,14 @@
than that number as sessions are cached based on their acknowledgment
mode, so there can be up to 4 cached session instances when
SessionCacheSize is set to one, one for each
<classname>AcknowledgementMode</classname>.
<classname>MessageProducers</classname> and
<classname>MessageConsumers</classname> are cached within their owning
<literal>AcknowledgementMode</literal>.
<literal>MessageProducers</literal> and
<literal>MessageConsumers</literal> are cached within their owning
session and also take into account the unique properties of the
producers and consumers when caching.</para>
<para><classname>MessageProducers</classname> are cached based on
their destination. <classname>MessageConsumers</classname> are cached
<para><literal>MessageProducers</literal> are cached based on
their destination. <literal>MessageConsumers</literal> are cached
based on a key composed of the destination, selector, noLocal delivery
flag, and the durable subscription name (if creating durable
consumers).</para>
@@ -323,7 +340,7 @@
administratively. You can use these vendor specific APIs to perform
dependency injection on references to JMS Destination objects in
Spring's XML configuration file by creating am implementation of
<classname>IObjectFactory</classname> or alternatively configuring the
<literal>IObjectFactory</literal> or alternatively configuring the
specific concrete class implementation for a messaging provider.</para>
<para>However, this approach of administered objects can be quite
@@ -332,12 +349,12 @@
unique to the messaging provider. Examples of such advanced destination
management would be the creation of dynamic destinations or support for
a hierarchical namespace of destinations. The
<classname>NmsTemplate</classname> delegates the resolution of a
<literal>NmsTemplate</literal> delegates the resolution of a
destination name to a destination object by delegating to an
implementation of the interface
<classname>IDestinationResolver</classname>.
<classname>DynamicDestinationResolver</classname> is the default
implementation used by <classname>NmsTemplate</classname> and
<literal>IDestinationResolver</literal>.
<literal>DynamicDestinationResolver</literal> is the default
implementation used by <literal>NmsTemplate</literal> and
accommodates resolving dynamic destinations.</para>
<para>Quite often the destinations used in a messaging application are
@@ -353,16 +370,16 @@
dynamic destinations varies from provider to provider since the
properties associated with the destination are vendor specific. However,
a simple implementation choice that is sometimes made by vendors is to
use the <classname>TopicSession</classname> method
use the <literal>TopicSession</literal> method
<literal>CreateTopic(string topicName)</literal> or the
<classname>QueueSession</classname> method <classname>CreateQueue(string
queueName)</classname> to create a new destination with default
<literal>QueueSession</literal> method <literal>CreateQueue(string
queueName)</literal> to create a new destination with default
destination properties. Depending on the vendor implementation,
<classname>DynamicDestinationResolver</classname> may then also create a
<literal>DynamicDestinationResolver</literal> may then also create a
physical destination instead of only resolving one.</para>
<para>The boolean property <literal>PubSubDomain</literal> is used to
configure the <classname>NmsTemplate</classname> with knowledge of what
configure the <literal>NmsTemplate</literal> with knowledge of what
messaging 'domain' is being used. By default the value of this property
is false, indicating that the point-to-point domain, Queues, will be
used. This property is infrequently used as the provider messaging APIs
@@ -370,10 +387,10 @@
referring to 'Destinations' rather than 'Queues' or 'Topics'. However,
this property does influence the behavior of dynamic destination
resolution via implementations of the
<classname>IDestinationResolver</classname> interface.</para>
<literal>IDestinationResolver</literal> interface.</para>
<para>You can also configure the NmsTemplate with a default destination
via the property <classname>DefaultDestination</classname>. The default
via the property <literal>DefaultDestination</literal>. The default
destination will be used with send and receive operations that do not
refer to a specific destination.</para>
</section>
@@ -384,7 +401,7 @@
<para>One of the most common uses of JMS is to concurrently process
messages delivered asynchronously. A message listener container is used
to receive messages from a message queue and drive the
<classname>IMessageListener</classname> that is injected into it. The
<literal>IMessageListener</literal> that is injected into it. The
listener container is responsible for all threading of message reception
and dispatches into the listener for processing. A message listener
container is the intermediary between an Message-Driven PONO (MDP) and a
@@ -396,11 +413,11 @@
infrastructure concerns to the framework.</para>
<para>A subclass of
<classname>AbstractMessageListenerContainer</classname> is used to
<literal>AbstractMessageListenerContainer</literal> is used to
receive messages from JMS and drive the Message-Driven PONOs (MDPs) that
are injected into it. There are one subclasses of
<classname>AbstractMessageListenerContainer</classname> packaged with
Spring - <classname>SimpleMessageListenerContainer</classname>.
<literal>AbstractMessageListenerContainer</literal> packaged with
Spring - <literal>SimpleMessageListenerContainer</literal>.
Additional subclasses, in particular to participate in distributed
transactions (if the provider supports it), will be provided in future
releases. SimpleMessageListenerContainer creates a fixed number of JMS
@@ -415,13 +432,13 @@
manages transactions for a single ConnectionFactory. This allows
messaging applications to leverage the managed transaction features of
Spring as described in <xref linkend="transaction" />. The
<classname>NmsTransactionManager</classname> performs local resource
<literal>NmsTransactionManager</literal> performs local resource
transactions, binding a Connection/Session pair from the specified
ConnectionFactory to the thread. <classname>NmsTemplate</classname>
ConnectionFactory to the thread. <literal>NmsTemplate</literal>
automatically detects such transactional resources and operates on them
accordingly.</para>
<para>Using Spring's <classname>SingleConnectionFactory</classname> will
<para>Using Spring's <literal>SingleConnectionFactory</literal> will
result in a shared Connection, with each transaction having its own
independent Session.</para>
</section>
@@ -430,7 +447,7 @@
<section>
<title>Sending a Message</title>
<para>The <classname>NmsTemplate</classname> contains three convenience
<para>The <literal>NmsTemplate</literal> contains three convenience
methods to send a message. The methods are listed below.</para>
<itemizedlist>
@@ -453,20 +470,20 @@
<para>The method differ in how the destination is specified. In first case
the JMS Destination object is specified directly. The second case
specifies the destination using a string that is then resolved to a
messaging <classname>Destination</classname> object using the
<classname>IDestinationResolver</classname> associated with the template.
messaging <literal>Destination</literal> object using the
<literal>IDestinationResolver</literal> associated with the template.
The last method sends the message to the destination specified by
<classname>NmsTemplate</classname>''s
<classname>DefaultDestination</classname> property.</para>
<literal>NmsTemplate</literal>''s
<literal>DefaultDestination</literal> property.</para>
<para>All methods take as an argument an instance of
<classname>IMessageCreator</classname> which defines the API contract for
<literal>IMessageCreator</literal> which defines the API contract for
you to create the JMS message. The interface is show below</para>
<para><programlisting>public interface IMessageCreator {
<para><programlisting language="csharp">public interface IMessageCreator {
IMessage CreateMessage(ISession session);
}</programlisting>Intermediate Sessions and MessageProducers needed to send
the message are managed by <classname>NmsTemplate</classname>. The session
the message are managed by <literal>NmsTemplate</literal>. The session
passed in to the method is never null. There is a similar set methods that
use a delegate instead of the interface, which can be convenient when
writing small implementation in .NET 2.0 using anonymous delegates.
@@ -492,7 +509,7 @@
<para>The declaration of the delegate is</para>
<programlisting>public delegate IMessage MessageCreatorDelegate(ISession session);</programlisting>
<programlisting language="csharp">public delegate IMessage MessageCreatorDelegate(ISession session);</programlisting>
<para>The following class shows how to use the SendWithDelegate method
with an anonymous delegate to create a MapMessage from the supplied
@@ -501,7 +518,7 @@
<literal>NmsTemplate</literal> is constructed by passing a reference to a
ConnectionFactory.</para>
<programlisting> public class SimplePublisher
<programlisting language="csharp"> public class SimplePublisher
{
private NmsTemplate template;
@@ -537,15 +554,15 @@
<title>Using MessageConverters</title>
<para>In order to facilitate the sending of domain model objects, the
<classname>NmsTemplate</classname> has various send methods that take a
<literal>NmsTemplate</literal> has various send methods that take a
.NET object as an argument for a message's data content. The overloaded
methods <classname>ConvertAndSend</classname> and
<classname>ReceiveAndConvert</classname> in
<classname>NmsTemplate</classname> delegate the conversion process to an
instance of the <interfacename>IMessageConverter</interfacename>
methods <literal>ConvertAndSend</literal> and
<literal>ReceiveAndConvert</literal> in
<literal>NmsTemplate</literal> delegate the conversion process to an
instance of the <literal>IMessageConverter</literal>
interface. This interface defines a simple contract to convert between
.NET objects and JMS messages. The default implementation
<classname>SimpleMessageConverter</classname> supports conversion
<literal>SimpleMessageConverter</literal> supports conversion
between String and TextMessage, byte[] and BytesMesssage, and
System.Collections.IDictionary and MapMessage. By using the converter,
you and your application code can focus on the business object that is
@@ -556,7 +573,7 @@
converts objects to an XML string and vice-versa for sending via a
TextMessage.</para>
<para>The family of <classname>ConvertAndSend</classname> messages are
<para>The family of <literal>ConvertAndSend</literal> messages are
similar to that of the Send method with the additional argument of type
IMessagePostProcessor. These methods are listed below.</para>
@@ -594,7 +611,7 @@
<para>The example below uses the default message converter to send a
Hashtable as a message to the destination "APP.STOCK".</para>
<para><programlisting>public void PublishUsingDict(string ticker, double price)
<para><programlisting language="csharp">public void PublishUsingDict(string ticker, double price)
{
IDictionary marketData = new Hashtable();
marketData.Add("TICKER", ticker);
@@ -602,12 +619,12 @@
template.ConvertAndSend("APP.STOCK.MARKETDATA", marketData);
}</programlisting>To accommodate the setting of message's properties, headers,
and body that can not be generally encapsulated inside a converter
class, the <classname>IMessageConverterPostProcessor</classname>
class, the <literal>IMessageConverterPostProcessor</literal>
interface gives you access to the message after it has been converted
but before it is sent. The example below demonstrates how to modify a
message header and a property after a Hashtable is converted to a
message using the IMessagePostProcessor. The methods
<classname>ConvertAndSendUsingDelegate</classname> allow for the use of
<literal>ConvertAndSendUsingDelegate</literal> allow for the use of
a delegate to perform message post processing. This family of methods is
listed below</para>
@@ -632,11 +649,11 @@
<para>The declaration of the delegate is</para>
<programlisting>public delegate IMessage MessagePostProcessorDelegate(IMessage message);</programlisting>
<programlisting language="csharp">public delegate IMessage MessagePostProcessorDelegate(IMessage message);</programlisting>
<para>The following code shows this in action.</para>
<para><programlisting>public void PublishUsingDict(string ticker, double price)
<para><programlisting language="csharp">public void PublishUsingDict(string ticker, double price)
{
IDictionary marketData = new Hashtable();
marketData.Add("TICKER", ticker);
@@ -685,12 +702,12 @@
<para>Where ISessionCallback and IProducerCallback are</para>
<para><programlisting>public interface IProducerCallback
<para><programlisting language="csharp">public interface IProducerCallback
{
object DoInJms(Session session, MessageProducer producer);
}</programlisting>and</para>
<programlisting>public interface ISessionCallback
<programlisting language="csharp">public interface ISessionCallback
{
object DoInJms(Session session);
}</programlisting>
@@ -698,7 +715,7 @@
<para>The delegate signatures are listed below and mirror the interface
method signature</para>
<programlisting>public delegate object SessionDelegate(ISession session);
<programlisting language="csharp">public delegate object SessionDelegate(ISession session);
public delegate object ProducerDelegate(ISession session, IMessageProducer producer);</programlisting>
</section>
@@ -712,12 +729,12 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ
<para>While messaging middleware is typically associated with
asynchronous processing, it is possible to consume messages
synchronously. The overloaded <code>Receive(..)</code> methods on
<classname>NmsTemplate</classname> provide this functionality. During a
<literal>NmsTemplate</literal> provide this functionality. During a
synchronous receive, the calling thread blocks until a message becomes
available. This can be a dangerous operation since the calling thread
can potentially be blocked indefinitely. The property
<code><property>ReceiveTimeout</property></code> on
<classname>NmsTemplate</classname> specifies how long the receiver
<literal>NmsTemplate</literal> specifies how long the receiver
should wait before giving up waiting for a message.</para>
<para>The <methodname>Receive</methodname> methods are listed
@@ -757,14 +774,14 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ
<para>The <methodname>Receive</methodname> method without arguments will
use the <property>DefaultDestination</property>. The
<methodname>ReceiveSelected</methodname> methods apply the provided
message selector string to the <classname>MessageConsumer</classname>
message selector string to the <literal>MessageConsumer</literal>
that is created.</para>
<para>The <methodname>ReceiveAndConvert</methodname> methods apply the
template's message converter when receiving a message. The message
converter to use is set using the property
<classname>MessageConverter</classname> and is the
<classname>SimpleMessageConverter</classname> implementation by default.
<literal>MessageConverter</literal> and is the
<literal>SimpleMessageConverter</literal> implementation by default.
These methods are listed below.</para>
<itemizedlist>
@@ -807,7 +824,7 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ
such as the IMessageListener interface shown below, taken from the TIBCO
EMS provider.</para>
<programlisting>public interface IMessageListener
<programlisting language="csharp">public interface IMessageListener
{
void OnMessage(Message message);
}</programlisting>
@@ -816,14 +833,14 @@ public delegate object ProducerDelegate(ISession session, IMessageProducer produ
callback or even both a delegate and interface options. Apache ActiveMQ
supports only the use of delegates for message reception callbacks. As a
programming convenience in
<classname>Spring.Messaging.Nms.Core</classname> is an interface
<classname>IMessageListener</classname> that can be used with
<literal>Spring.Messaging.Nms.Core</literal> is an interface
<literal>IMessageListener</literal> that can be used with
NMS.</para>
<para>Below is a simple implementation of the IMessageListener interface
that processing a message.</para>
<programlisting>using Spring.Messaging.Nms.Core;
<programlisting language="csharp">using Spring.Messaging.Nms.Core;
using Apache.NMS;
using Common.Logging;
@@ -862,15 +879,15 @@ namespace MyApp
specifies various messaging configuration parameters, such as the
ConnectionFactory, and the number of concurrent consumers to create.
There is an abstract base class for message listener containers,
<classname>AbstractMessageListenerContainer</classname>, and one
<literal>AbstractMessageListenerContainer</literal>, and one
concrete implementation,
<classname>SimpleMessageListenerContainer</classname>.
<classname>SimpleMessageListenerContainer</classname> creates a fixed
<literal>SimpleMessageListenerContainer</literal>.
<literal>SimpleMessageListenerContainer</literal> creates a fixed
number of JMS Sessions/MessageConsumer pairs as set by the property
<property>ConcurrentConsumers</property>. Here is a sample
configuration</para>
<programlisting>
<programlisting language="myxml">
&lt;object id="ConnectionFactory" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ"&gt;
&lt;constructor-arg index="0" value="tcp://localhost:61616"/&gt;
&lt;/object&gt;
@@ -895,14 +912,14 @@ namespace MyApp
via the properties <property>SubscriptionDurable</property> and
<property>DurableSubscriptionName</property>. You may also register an
exception listener using the property
<classname>ExceptionListener</classname>.</para>
<literal>ExceptionListener</literal>.</para>
<para>A custom schema to create the
<classname>SimpleMessageListener</classname> container is also provided.
<literal>SimpleMessageListener</literal> container is also provided.
Using this schema the configuration above looks like the
following</para>
<programlisting>&lt;objects xmlns="http://www.springframework.net"
<programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"
xmlns:nms="http://www.springframework.net/nms"&gt;
&lt;!-- other object definitions --&gt;
@@ -913,35 +930,35 @@ namespace MyApp
&lt;/objects&gt;</programlisting>
<para>Exceptions that are thrown during message processing can be passed
to an implementation of <classname>IExceptionHandler</classname> and
to an implementation of <literal>IExceptionHandler</literal> and
registered with the container via the property
<classname>ExceptionListener</classname>. The registered
<classname>IExceptionHandler</classname> will be invoked if the
exception is of the type <classname>NMSException</classname> (or the
<literal>ExceptionListener</literal>. The registered
<literal>IExceptionHandler</literal> will be invoked if the
exception is of the type <literal>NMSException</literal> (or the
equivalent root exception type for other providers). The
SimpleMessageListenerContainer will logs the exception at error level
and not propagate the exception to the provider. All handling of
acknowledgement and/or transactions is done by the listener container.
You can override the method
<classname>HandleListenerException</classname> to change this
<literal>HandleListenerException</literal> to change this
behavior.</para>
<para>Please refer to the Spring SDK documentation for additional
description of the features and properties of
<classname>SimpleMessageListenerContainer</classname>.</para>
<literal>SimpleMessageListenerContainer</literal>.</para>
</section>
<section>
<title>The ISessionAwareMessageListener interface</title>
<para>The <classname>ISessionAwareMessageListener</classname> interface
<para>The <literal>ISessionAwareMessageListener</literal> interface
is a Spring-specific interface that provides a similar contract to the
messaging provider's <classname>IMessageListener</classname> interface
messaging provider's <literal>IMessageListener</literal> interface
or Listener delegate/event, but also provides the message handling
method with access to the Session from which the Message was
received.</para>
<programlisting>public interface ISessionAwareMessageListener
<programlisting language="csharp">public interface ISessionAwareMessageListener
{
void OnMessage(IMessage message, ISession session);
}</programlisting>
@@ -950,7 +967,7 @@ namespace MyApp
with the message listener container</para>
</section>
<section id="message-listener-adapter">
<section xml:id="message-listener-adapter">
<title>MessageListenerAdapater</title>
<para>The MessageListenerAdapter class is the final component in
@@ -960,15 +977,15 @@ namespace MyApp
<para>Consider the following interface definition. Notice that although
the interface extends neither the
<classname>IMessageListener</classname> nor
<classname>ISessionAwareMessageListener</classname> interfaces, it can
<literal>IMessageListener</literal> nor
<literal>ISessionAwareMessageListener</literal> interfaces, it can
still be used as a Message-Driven PONOs (MDP) via the use of the
<classname>MessageListenerAdapter</classname> class. Notice also how the
<literal>MessageListenerAdapter</literal> class. Notice also how the
various message handling methods are strongly typed according to the
contents of the various Message types that they can receive and
handle.</para>
<programlisting>public interface MessageHandler {
<programlisting language="csharp">public interface MessageHandler {
void HandleMessage(string message);
@@ -980,7 +997,7 @@ namespace MyApp
<para>and a class that implements this interface...</para>
<programlisting>public class DefaultMessageHandler : IMessageHandler {
<programlisting language="csharp">public class DefaultMessageHandler : IMessageHandler {
// stub implementations elided for bevity...
}</programlisting>
@@ -989,16 +1006,16 @@ namespace MyApp
messaging provider API dependencies at all. It truly is a PONO that we
will make into an MDP via the following configuration.</para>
<programlisting><emphasis role="bold">&lt;object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/&gt;</emphasis>
<programlisting language="myxml">&lt;object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/&gt;
&lt;object id="MessageListenerAdapter" type="Spring.Messaging.Nms.Listener.Adapter.MessageListenerAdapter, Spring.Messaging.Nms"&gt;
<emphasis role="bold">&lt;property name="HandlerObject" ref="MessagleHandler"/&gt;</emphasis>
&lt;property name="HandlerObject" ref="MessagleHandler"/&gt;
&lt;/object&gt;
&lt;object id="MessageListenerContainer" type="Spring.Messaging.Nms.Listener.SimpleMessageListenerContainer, Spring.Messaging.Nms"&gt;
&lt;property name="ConnectionFactory" ref="ConnectionFactory"/&gt;
&lt;property name="DestinationName" value="APP.REQUEST"/&gt;
<emphasis role="bold">&lt;property name="MessageListener" ref="MessageListenerAdapter"/&gt;</emphasis>
&lt;property name="MessageListener" ref="MessageListenerAdapter"/&gt;
&lt;/object&gt;</programlisting>
<para>The previous examples relies on the fact that the default
@@ -1015,23 +1032,23 @@ namespace MyApp
'Receive(..)' method is strongly typed to receive and respond only to
NMS ITextMessage messages.</para>
<programlisting>public interface TextMessageHandler {
<programlisting language="csharp">public interface TextMessageHandler {
void Receive(ITextMessage message);
}</programlisting>
<programlisting>public class TextMessageHandler implements ITextMessageHandler {
<programlisting language="csharp">public class TextMessageHandler implements ITextMessageHandler {
// implementation elided for clarity...
}</programlisting>
<para>The configuration of the attendant
<classname>MessageListenerAdapter</classname> would look like
<literal>MessageListenerAdapter</literal> would look like
this</para>
<programlisting><emphasis role="bold">&lt;object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/&gt;</emphasis>
<programlisting language="myxml">&lt;object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/&gt;
&lt;object id="MessageListenerAdapter" type="Spring.Messaging.Nms.Listener.Adapter.MessageListenerAdapter, Spring.Messaging.Nms"&gt;
<emphasis role="bold">&lt;property name="HandlerObject" ref="TextMessagleHandler"/&gt;</emphasis>
&lt;property name="HandlerObject" ref="TextMessagleHandler"/&gt;
&lt;property name="DefaultHandlerMethod" value="Receive"/&gt;
&lt;!-- we don't want automatic message context extraction --&gt;
&lt;property name="MessageConverter"&gt;
@@ -1041,18 +1058,18 @@ namespace MyApp
<para>Please note that if the above 'MessageListener' receives a Message
of a type other than ITextMessage, a
<classname>ListenerExecutionFailedException</classname> will be thrown
<literal>ListenerExecutionFailedException</literal> will be thrown
(and subsequently handled by the container by logging the
exception).</para>
<para>If your <classname>IMessageConverter</classname> implementation
<para>If your <literal>IMessageConverter</literal> implementation
will return multiple object types, overloading the handler method is
perfectly acceptable, the most specific matching method will be used. A
method with an object signature would be consider a 'catch-all' method
of last resort. For example, you can have an handler interface as shown
below.</para>
<para><programlisting>public interface IMyHandler
<para><programlisting language="csharp">public interface IMyHandler
{
void DoWork(string text);
void DoWork(OrderRequest orderRequest);
@@ -1068,7 +1085,7 @@ namespace MyApp
property of the original Message (if one exists) , or the default
Destination set on the MessageListenerAdapter (if one has been
configured). If no Destination is found then an
<classname>InvalidDestinationException</classname> will be thrown (and
<literal>InvalidDestinationException</literal> will be thrown (and
please note that this exception will not be swallowed and will propagate
up the call stack).</para>
@@ -1076,7 +1093,7 @@ namespace MyApp
that supports multiple object types and has return values is shown
below.</para>
<programlisting>public interface IMyHandler
<programlisting language="csharp">public interface IMyHandler
{
string DoWork(string text);
OrderResponse DoWork(OrderRequest orderRequest);
@@ -1120,7 +1137,7 @@ namespace MyApp
more &lt;listener/&gt; child elements. Here is an example of a basic
configuration for two listeners.</para>
<programlisting>&lt;nms:listener-container&gt;
<programlisting language="myxml">&lt;nms:listener-container&gt;
&lt;nms:listener destination="queue.orders" ref="OrderService" method="PlaceOrder"/&gt;
@@ -1166,7 +1183,7 @@ namespace MyApp
role="bold">(required)</emphasis></entry>
<entry><para>The destination name for this listener, resolved
through the <interfacename>IDestinationResolver</interfacename>
through the <literal>IDestinationResolver</literal>
strategy.</para></entry>
</row>
@@ -1182,8 +1199,8 @@ namespace MyApp
<entry><para>The name of the handler method to invoke. If the
<literal>ref</literal> points to a
<interfacename>IMessageListener</interfacename> or Spring
<interfacename>ISessionAwareMessageListener</interfacename>,
<literal>IMessageListener</literal> or Spring
<literal>ISessionAwareMessageListener</literal>,
this attribute may be omitted.</para></entry>
</row>
@@ -1234,7 +1251,7 @@ namespace MyApp
to define highly-customized listener containers while still benefiting
from the convenience of the namespace.</para>
<programlisting>&lt;jms:listener-container connection-factory="MyConnectionFactory"
<programlisting language="myxml">&lt;jms:listener-container connection-factory="MyConnectionFactory"
destination-resolver="MyDestinationResolver"
concurrency="10"&gt;
@@ -1246,8 +1263,8 @@ namespace MyApp
<para>The following table describes all available attributes. Consult
the class-level SDK documentation of the
<classname>AbstractMessageListenerContainer</classname> and its subclass
<classname>SimpleMessageListenerContainer</classname> for more detail on
<literal>AbstractMessageListenerContainer</literal> and its subclass
<literal>SimpleMessageListenerContainer</literal> for more detail on
the individual properties.</para>
<table id="nms-namespace-listener-container-tbl">
@@ -1272,7 +1289,7 @@ namespace MyApp
<entry>connection-factory</entry>
<entry><para>A reference to the NMS
<interfacename>ConnectionFactory</interfacename> object (the
<literal>ConnectionFactory</literal> object (the
default object name is
<literal>'ConnectionFactory'</literal>).</para></entry>
</row>
@@ -1281,18 +1298,18 @@ namespace MyApp
<entry>destination-resolver</entry>
<entry><para>A reference to the
<interfacename>IDestinationResolver</interfacename> strategy for
<literal>IDestinationResolver</literal> strategy for
resolving JMS
<interfacename>Destinations</interfacename>.</para></entry>
<literal>Destinations</literal>.</para></entry>
</row>
<row>
<entry>message-converter</entry>
<entry><para>A reference to the
<interfacename>IMessageConverter</interfacename> strategy for
<literal>IMessageConverter</literal> strategy for
converting NMS Messages to listener method arguments. Default is
a <classname>SimpleMessageConverter</classname>.</para></entry>
a <literal>SimpleMessageConverter</literal>.</para></entry>
</row>
<row>
@@ -1319,7 +1336,7 @@ namespace MyApp
<literal>auto</literal>, <literal>client</literal>,
<literal>dups-ok</literal> or <literal>transacted</literal>. A
value of <literal>transacted</literal> activates a locally
transacted <interfacename>Session</interfacename>. As an
transacted <literal>Session</literal>. As an
alternative, specify the <literal>transaction-manager</literal>
attribute described below. Default is
<literal>auto</literal>.</para></entry>

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="migration">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="migration" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Migrating from 1.1 M2</title>
<sect1 id="M2RC1-introduction">
<sect1 xml:id="M2RC1-introduction">
<title>Introduction</title>
<para>Several API changes were made after 1.1 M2 (before 1.1 RC1)due
@@ -19,7 +36,7 @@
and higher</para>
</sect1>
<sect1 id="migration-changes">
<sect1 xml:id="migration-changes">
<title>Important Changes</title>
<para>This section covers the common areas were you will need to make
@@ -35,39 +52,39 @@
<para>The names of the section handlers to register custom schemas has
changed, from ConfigParsersSectionHandler to
<classname>NamespaceParsersSectionHandler</classname>.</para>
<literal>NamespaceParsersSectionHandler</literal>.</para>
<para>The target namespaces have changed, the 'directory' named /schema/
has been removed. For example, the target schema changed from
http://www.springframework.net/schema/tx to
<classname>http://www.springframework.net/tx.</classname></para>
<literal>http://www.springframework.net/tx.</literal></para>
<para>A typical declaration to use custom schemas within your
configuration file looks like this</para>
<programlisting>&lt;objects xmlns='http://www.springframework.net'
<programlisting language="myxml">&lt;objects xmlns='http://www.springframework.net'
xmlns:db="http://www.springframework.net/database"
xmlns:tx="http://www.springframework.net/tx"
xmlns:aop="http://www.springframework.net/aop"&gt;</programlisting>
<para>The class <classname>XmlParserRegistry</classname> was renamed to
<classname>NamespaceParserRegistry</classname>.</para>
<para>The class <literal>XmlParserRegistry</literal> was renamed to
<literal>NamespaceParserRegistry</literal>.</para>
<para>Renamed
<classname>Spring.Validation.ValidationConfigParser</classname> to
<classname>Spring.Validation.Config.ValidationNamespaceParser</classname></para>
<literal>Spring.Validation.ValidationConfigParser</literal> to
<literal>Spring.Validation.Config.ValidationNamespaceParser</literal></para>
<para>Renamed from <classname>DatabaseConfigParser</classname> to
<classname>DatabaseNamespaceParser</classname></para>
<para>Renamed from <literal>DatabaseConfigParser</literal> to
<literal>DatabaseNamespaceParser</literal></para>
<para>Renamed/Moved <classname>Remoting.RemotingConfigParser</classname>
<para>Renamed/Moved <literal>Remoting.RemotingConfigParser</literal>
to
<classname>Remoting.Config.RemotingNamespaceParser</classname><parameter></parameter></para>
<literal>Remoting.Config.RemotingNamespaceParser</literal><parameter></parameter></para>
<para>A typical registration of custom parsers within your configuration
file looks like this</para>
<programlisting>&lt;configuration&gt;
<programlisting language="myxml">&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
@@ -85,7 +102,7 @@
<para>A manual registration would look like this</para>
<programlisting>NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));
<programlisting language="csharp">NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));
NamespaceParserRegistry.RegisterParser(typeof(DatabaseNamespaceParser));
NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser));
</programlisting>

View File

@@ -1,4 +1,22 @@
<chapter id="misc">
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="misc" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Spring.NET miscellanea</title>
<sect1>
<title>Introduction</title>
@@ -23,12 +41,10 @@
features.
</para>
<para>To do the match, you use the method:
<programlisting format='linespecific' xml:space='preserve'>
tatic bool Match(string pattern, string path)</programlisting>
<programlisting language="csharp">static bool Match(string pattern, string path)</programlisting>
</para>
<para>If you want to decide if case is important or not use the method:
<programlisting format='linespecific' xml:space='preserve'>
tatic bool Match(string pattern, string path, bool ignoreCase)</programlisting>
<programlisting language="csharp">static bool Match(string pattern, string path, bool ignoreCase)</programlisting>
</para>
<sect2>
<title>General rules</title>
@@ -60,35 +76,29 @@ tatic bool Match(string pattern, string path, bool ignoreCase)</programlisting>
<para>
A file name can be matched using the following
notation:
<programlisting format='linespecific' xml:space='preserve'>
foo?bar.*</programlisting>
<programlisting>foo?bar.*</programlisting>
matches:
<programlisting format='linespecific' xml:space='preserve'>
fooAbar.txt
<programlisting>fooAbar.txt
foo1bar.txt
foo_bar.txt
foo-bar.txt</programlisting>
does not match:
<programlisting format='linespecific' xml:space='preserve'>
foo.bar.txt
<programlisting>foo.bar.txt
foo/bar.txt
foo\bar.txt</programlisting>
</para>
<para>
The classical all files pattern:
<programlisting format='linespecific' xml:space='preserve'>
*.*</programlisting>
<programlisting>*.*</programlisting>
matches:
<programlisting format='linespecific' xml:space='preserve'>
foo.db
<programlisting>foo.db
.db
foo
foo.bar.db
foo.db.db
db.db.db</programlisting>
does not match:
<programlisting format='linespecific' xml:space='preserve'>
c:/
<programlisting>c:/
c:/foo.db
c:/foo
c:/.db
@@ -102,48 +112,39 @@ c:/foo.foo.db
<para>
A directory name can be matched at any depth level using the following
notation:
<programlisting format='linespecific' xml:space='preserve'>
**/db/**</programlisting>
<programlisting>**/db/**</programlisting>
That pattern matches the following paths:
<programlisting format='linespecific' xml:space='preserve'>
/db
<programlisting>/db
//server/db
c:/db
c:/spring/app/db/foo.db
//Program Files/App/spaced dir/db/foo.db
/home/spring/spaced dir/db/v1/foo.db</programlisting>
but does not match these:
<programlisting format='linespecific' xml:space='preserve'>
c:/spring/app/db-v1/foo.db
<programlisting>c:/spring/app/db-v1/foo.db
/home/spring/spaced dir/db-v1/foo.db</programlisting>
</para>
<para>
You can compose subdirectories to match like this:
<programlisting format='linespecific' xml:space='preserve'>
**/bin/**/tmp/**</programlisting>
<programlisting>**/bin/**/tmp/**</programlisting>
That pattern matches the following paths:
<programlisting format='linespecific' xml:space='preserve'>
c:/spring/foo/bin/bar/tmp/a
<programlisting>c:/spring/foo/bin/bar/tmp/a
c:/spring/foo/bin/tmp/a/b.c</programlisting>
but does not match these:
<programlisting format='linespecific' xml:space='preserve'>
c:/spring/foo/bin/bar/temp/a
<programlisting>c:/spring/foo/bin/bar/temp/a
c:/tmp/foo/bin/bar/a/b.c</programlisting>
</para>
<para>
You can use more advanced patterns:
<programlisting format='linespecific' xml:space='preserve'>
**/.spring-assemblies*/**</programlisting>
<programlisting>**/.spring-assemblies*/**</programlisting>
matches:
<programlisting format='linespecific' xml:space='preserve'>
c:/.spring-assemblies
<programlisting>c:/.spring-assemblies
c:/.spring-assembliesabcd73xs
c:/app/.spring-assembliesabcd73xs
c:/app/.spring-assembliesabcd73xs/foo.dll
//server/app/.spring-assembliesabcd73xs</programlisting>
does not match:
<programlisting format='linespecific' xml:space='preserve'>
c:/app/.spring-assemblie</programlisting>
<programlisting>c:/app/.spring-assemblie</programlisting>
</para>
</sect2>
@@ -153,14 +154,11 @@ c:/app/.spring-assemblie</programlisting>
.NET is expected to be a cross-platform development ... platform. So,
<literal>PathMatcher</literal> will match taking care of the case of the pattern
and the case of the path. For example:
<programlisting format='linespecific' xml:space='preserve'>
**/db/**/*.DB</programlisting>
<programlisting>**/db/**/*.DB</programlisting>
matches:
<programlisting format='linespecific' xml:space='preserve'>
c:/spring/service/deploy/app/db/foo.DB</programlisting>
<programlisting>c:/spring/service/deploy/app/db/foo.DB</programlisting>
but does not match:
<programlisting format='linespecific' xml:space='preserve'>
c:/spring/service/deploy/app/DB/foo.DB
<programlisting>c:/spring/service/deploy/app/DB/foo.DB
c:spring/service/deploy/app/spaced dir/DB/foo.DB
//server/share/service/deploy/app/DB/backup/foo.db</programlisting>
</para>
@@ -169,11 +167,9 @@ c:spring/service/deploy/app/spaced dir/DB/foo.DB
<para>
Back and forward slashes, in the very same cross-platform spirit, are
not important:
<programlisting format='linespecific' xml:space='preserve'>
spring/foo.bar</programlisting>
<programlisting>spring/foo.bar</programlisting>
matches all the following paths:
<programlisting format='linespecific' xml:space='preserve'>
c:\spring\foo.bar
<programlisting>c:\spring\foo.bar
c:/spring\foo.bar
c:/spring/foo.bar
/spring/foo.bar

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,24 @@
<chapter id="navigation">
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="navigation" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Object Navigation</title>
<sect1 id="navigation-introduction">
<sect1 xml:id="navigation-introduction">
<title>Introduction</title>
<para><emphasis>(Available in 1.0)</emphasis></para>
<para>Spring provides an expression language that allows for the easy setting
@@ -19,11 +37,11 @@
contained in the <literal>Spring.Web</literal> library uses this expression language.
</para>
</sect1>
<sect1 id="navigation-simpleexprssions">
<sect1 xml:id="navigation-simpleexprssions">
<title>Simple Expressions</title>
<para>
Consider the simple class shown below with the
public field <literal>Name</literal><programlisting>
public field <literal>Name</literal><programlisting language="csharp">
public class Inventor
{
public string Name;
@@ -37,21 +55,21 @@ public class Inventor
}
</programlisting>
which may have been instantiated in code somewhere and had its Name
and DOB set to particular values<programlisting>Inventor inventor = new Inventor();
and DOB set to particular values<programlisting language="csharp">Inventor inventor = new Inventor();
inventor.Name = "Nikola Tesla";
inventor.DOB = new DateTime(1854, 10, 9);
</programlisting>
The <classname>ObjectNavigator</classname> is the central
The <literal>ObjectNavigator</literal> is the central
class used to set or retrieve the value of an object, and contains
the following static methods
<programlisting>
<programlisting language="csharp">
object GetValue(object root, string expression)
object GetValue(object root, NavigationExpression expression)
void SetValue(object root, string expression, object newValue)
void SetValue(object root, NavigationExpression expression, object newValue)
</programlisting>
To retrieve the name and year of birth we can use the following code<programlisting>
To retrieve the name and year of birth we can use the following code<programlisting language="csharp">
string name = (string) ObjectNavigator.GetValue(inventor, "Name");
int year = (int) ObjectNavigator.GetValue(inventor, "DOB.Year");
</programlisting>
@@ -61,13 +79,13 @@ int year = (int) ObjectNavigator.GetValue(inventor, "DOB.Year");
evaluate a complex expression frequently, creating a
<literal>NavigationExpression</literal>
and reusing it will increase performance. To set the property values of this
object instance to that of another famous inventor we would write<programlisting>
object instance to that of another famous inventor we would write<programlisting language="csharp">
ObjectNavigator.SetValue(inventor, "Name", "Michael Pupin");
ObjectNavigator.SetValue(inventor, "DOB", new DateTime(1854, 10, 9));
</programlisting>
</para>
</sect1>
<sect1 id="navigation-collections">
<sect1 xml:id="navigation-collections">
<title>Navigating Collections</title>
<para>TODO. TestCase shows some example usage. Please check the Spring.NET <ulink url="http://www.springframework.net/doc/reference/navigation.html">website</ulink> for the latest updates to this document.
</para>

View File

@@ -1,5 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="nms-quickstart">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="nms-quickstart" xmlns="http://docbook.org/ns/docbook" version="5">
<title>NMS QuickStart</title>
<section>
@@ -58,51 +75,51 @@
<para>Queues are shown in red and topics in green.</para>
</section>
<section id="nms-gateways">
<section xml:id="nms-gateways">
<title>Gateways</title>
<para>Gateways represent the service operation to send a message. The
client will send a stock request to the server based on the contract
defined by the <classname>IStockService</classname> interface .</para>
defined by the <literal>IStockService</literal> interface .</para>
<programlisting> public interface IStockService
<programlisting language="csharp"> public interface IStockService
{
void Send(TradeRequest tradeRequest);
}</programlisting>
<para>The server will send market data to the clients based on the
contract defined by the <classname>IMarketDataService</classname>
contract defined by the <literal>IMarketDataService</literal>
interface.</para>
<programlisting> public interface IMarketDataService
<programlisting language="csharp"> public interface IMarketDataService
{
void SendMarketData();
}</programlisting>
<para>The market data gateway has no method parameters as it is assumed
that implementations will manage the data to send internally. The
<classname>TradeRequest</classname> object is one of the data objects that
<literal>TradeRequest</literal> object is one of the data objects that
will be exchanged in the application and is discussed in the next
section.</para>
<para>The use of interfaces allows for multiple implementations to be
created. Implementations that use messaging to communicate will be based
on the Spring's <classname>NmsGateway</classname> class and will be
on the Spring's <literal>NmsGateway</literal> class and will be
discussed later. stub or mock implementations can be used for testing
purposes.</para>
</section>
<section id="nms-messagedata">
<section xml:id="nms-messagedata">
<title>Message Data</title>
<para>The <classname>TradeRequest</classname> object shown above contains
<para>The <literal>TradeRequest</literal> object shown above contains
all the information required to process a stock order. To promote the
interoperability of this data across different platforms the
<classname>TradeRequest</classname> class is generated from an XML Schema
<literal>TradeRequest</literal> class is generated from an XML Schema
using Microsoft's Schema Definition Tool (xsd.exe). The schema for trade
request is shown below</para>
<programlisting>&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
<programlisting language="myxml">&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://www.springframework.net/nms/common/2008-08-05"&gt;
&lt;xs:element name="TradeRequest"&gt;
@@ -127,7 +144,7 @@
properties for each of the element names. A partial code listing of the
TradeRequest class is shown below</para>
<programlisting>// This code was generated by a tool.
<programlisting language="csharp">// This code was generated by a tool.
public partial class TradeRequest {
public string Ticker {
@@ -152,16 +169,16 @@
}</programlisting>
<para>The schema and the <classname>TradeRequest</classname> class are
located in the project <classname>Spring.NmsQuickStart.Common</classname>.
<para>The schema and the <literal>TradeRequest</literal> class are
located in the project <literal>Spring.NmsQuickStart.Common</literal>.
This common project will be shared between the server and client for
convenience.</para>
<para>When sending a response back to the client the type
<classname>TradeResponse</classname> will be used. The schema for the
<classname>TradeResponse</classname> is shown below</para>
<literal>TradeResponse</literal> will be used. The schema for the
<literal>TradeResponse</literal> is shown below</para>
<programlisting>&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
<programlisting language="myxml">&lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://www.springframework.net/nms/common/2008-08-05"&gt;
&lt;xs:element name="TradeResponse"&gt;
@@ -179,10 +196,10 @@
&lt;/xs:schema&gt;</programlisting>
<para>The <classname>TradeResponse</classname> type also generated from a
<para>The <literal>TradeResponse</literal> type also generated from a
schema using xsd.exe. A partial code listing is shown below</para>
<programlisting>// This code was generated by a tool.
<programlisting language="csharp">// This code was generated by a tool.
public partial class TradeResponse {
@@ -212,15 +229,15 @@
structure.</para>
</section>
<section id="nms-handlers">
<section xml:id="nms-handlers">
<title>Message Handlers</title>
<para>When the <classname>TradeRequest</classname> message is received by
<para>When the <literal>TradeRequest</literal> message is received by
the server, it will be handled by the class
<classname>Spring.NmsQuickStart.Server.Handlers.StockAppHandler
</classname>shown below</para>
<literal>Spring.NmsQuickStart.Server.Handlers.StockAppHandler
</literal>shown below</para>
<programlisting> public class StockAppHandler
<programlisting language="csharp"> public class StockAppHandler
{
private IExecutionVenueService executionVenueService;
@@ -260,7 +277,7 @@
client is the class Spring.NmsQuickStart.Client.Handlers.StockAppHandler
and is shown below.</para>
<programlisting> public class StockAppHandler
<programlisting language="csharp"> public class StockAppHandler
{
// definition of stockController omitted for brevity.
@@ -292,10 +309,10 @@
<title>Message Converters</title>
<para>The implementation of IMessageConverter used is
<classname>Spring.NmsQuickStart.Common.Converters.XmlMessageConverter</classname>.
<literal>Spring.NmsQuickStart.Common.Converters.XmlMessageConverter</literal>.
This converter adds the ability to marshal and unmarshal objects to and
from XML strings. It also uses Spring's
<classname>SimpleMessageConverter</classname> to convert Hashtables,
<literal>SimpleMessageConverter</literal> to convert Hashtables,
strings, and byte arrays. In order to pass information about the
serialized type, type information is put in the message properties. The
type information can be either the class name or an integer value
@@ -305,7 +322,7 @@
The XML configuration used to configure these objects is shown
below</para>
<programlisting> &lt;object name="XmlMessageConverter" type="Spring.NmsQuickStart.Common.Converters.XmlMessageConverter, Spring.NmsQuickStart.Common"&gt;
<programlisting language="myxml"> &lt;object name="XmlMessageConverter" type="Spring.NmsQuickStart.Common.Converters.XmlMessageConverter, Spring.NmsQuickStart.Common"&gt;
&lt;property name="TypeMapper" ref="TypeMapper"/&gt;
&lt;/object&gt;
@@ -323,11 +340,11 @@
<title>Messaging Infrastructure</title>
<para>The implementations of the gateway interfaces inherit from Spring's
helper class <classname>NmsGatewaySupport</classname> in order to get easy
helper class <literal>NmsGatewaySupport</literal> in order to get easy
access to a NmsTemplate for sending. The implementation of the
<classname>IStockService</classname> interface is shown below</para>
<literal>IStockService</literal> interface is shown below</para>
<programlisting> public class NmsStockServiceGateway : NmsGatewaySupport, IStockService
<programlisting language="csharp"> public class NmsStockServiceGateway : NmsGatewaySupport, IStockService
{
private IDestination defaultReplyToQueue;
@@ -347,7 +364,7 @@
}
}</programlisting>
<para>The <classname>Send</classname> method is using NmsTemplate's
<para>The <literal>Send</literal> method is using NmsTemplate's
<literal>ConvertAndSendWithDelegate(object obj,
MessagePostProcessorDelegate messagePostProcessorDelegate)</literal>
method. The anonymous delegate allows you to modify the message
@@ -357,12 +374,13 @@
logic to the converted message.</para>
<para>The object definition for the
<classname>NmsStockServiceGateway</classname> is shown below along with
<literal>NmsStockServiceGateway</literal> is shown below along with
its dependent object definitions of NmsTemplate and the
ConnectionFactory.</para>
<para><programlisting> &lt;object name="StockServiceGateway" type="Spring.NmsQuickStart.Client.Gateways.NmsStockServiceGateway, Spring.NmsQuickStart.Client"&gt;
&lt;property name="NmsTemplate" ref="<emphasis role="bold">NmsTemplate</emphasis>"/&gt;
<para>
<programlisting language="myxml"> &lt;object name="StockServiceGateway" type="Spring.NmsQuickStart.Client.Gateways.NmsStockServiceGateway, Spring.NmsQuickStart.Client"&gt;
&lt;property name="NmsTemplate" ref="NmsTemplate"/&gt;
&lt;property name="DefaultReplyToQueue"&gt;
&lt;object type="Apache.NMS.ActiveMQ.Commands.ActiveMQQueue, Apache.NMS.ActiveMQ"&gt;
&lt;constructor-arg value="APP.STOCK.JOE"/&gt;
@@ -370,32 +388,32 @@
&lt;/property&gt;
&lt;/object&gt;
&lt;object name="<emphasis role="bold">NmsTemplate</emphasis>" type="Spring.Messaging.Nms.Core.NmsTemplate, Spring.Messaging.Nms"&gt;
&lt;property name="ConnectionFactory" ref="<emphasis role="bold">ConnectionFactory</emphasis>"/&gt;
&lt;object name="NmsTemplate" type="Spring.Messaging.Nms.Core.NmsTemplate, Spring.Messaging.Nms"&gt;
&lt;property name="ConnectionFactory" ref="ConnectionFactory"/&gt;
&lt;property name="DefaultDestinationName" value="APP.STOCK.REQUEST"/&gt;
&lt;property name="MessageConverter" ref="XmlMessageConverter"/&gt;
&lt;/object&gt;
&lt;object id="<emphasis role="bold">ConnectionFactory</emphasis>" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ"&gt;
&lt;object id="ConnectionFactory" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ"&gt;
&lt;constructor-arg index="0" value="tcp://localhost:61616"/&gt;
&lt;/object&gt;</programlisting>In this example the 'raw'
<classname>Apache.NMS.ActiveMQ.ConnectionFactory </classname>connection
<literal>Apache.NMS.ActiveMQ.ConnectionFactory </literal>connection
factory was used. It would be more efficient resource wise to use Spring's
<classname>CachingConnectionFactory</classname> wrapper class so that
<literal>CachingConnectionFactory</literal> wrapper class so that
connections will not be open and closed for each message send as well as
allowing for the caching of other intermediate NMS API objects such as
sessions and message producers.</para>
<para>A similar configuration is used on the server to configure the class
<classname>Spring.NmsQuickStart.Server.Gateways.MarketDataServiceGateway
</classname>that implements the <classname>IMarketDataService</classname>
<literal>Spring.NmsQuickStart.Server.Gateways.MarketDataServiceGateway
</literal>that implements the <literal>IMarketDataService</literal>
interface.</para>
<para>Since the client is also a consumer of messages, on the topic
APP.STOCK.MARKETDATA and the queue APP.STOCK.JOE (for Trader Joe!), two
message listener containers are defined as shown below.</para>
<programlisting> &lt;nms:listener-container connection-factory="ConnectionFactory"&gt;
<programlisting language="myxml"> &lt;nms:listener-container connection-factory="ConnectionFactory"&gt;
&lt;nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.JOE" /&gt;
&lt;nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.MARKETDATA" pubsub-domain="true"/&gt;
&lt;/nms:listener-container&gt;</programlisting>
@@ -410,7 +428,7 @@
APP.STOCK.REQUEST but set the concurrency property to 10 so that 10
threads will be consuming messages from the queue.</para>
<programlisting> &lt;nms:listener-container connection-factory="ConnectionFactory" concurrency="<emphasis
<programlisting language="myxml"> &lt;nms:listener-container connection-factory="ConnectionFactory" concurrency="<emphasis
role="bold">10</emphasis>"&gt;
&lt;nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.REQUEST" /&gt;
&lt;/nms:listener-container&gt;</programlisting>

View File

@@ -1,50 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="objects-misc">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="objects-misc" xmlns="http://docbook.org/ns/docbook" version="5">
<title>The IObjectWrapper and Type conversion</title>
<sect1 id="objects-misc-introduction">
<sect1 xml:id="objects-misc-introduction">
<title>Introduction</title>
<para>The concepts encapsulated by the
<classname>IObjectWrapper</classname> interface are fundamental to the
<literal>IObjectWrapper</literal> interface are fundamental to the
workings of the core Spring.NET libraries The typical application
developer most probably will not ever have the need to use the
<classname>IObjectWrapper</classname> directly... because this is
<literal>IObjectWrapper</literal> directly... because this is
reference documentation however, we felt that some explanation of this
core interface might be right. The <classname>IObjectWrapper</classname>
core interface might be right. The <literal>IObjectWrapper</literal>
is explained in this chapter since if you were going to use it at all, you
would probably do that when trying to bind data to objects, which, nicely
enough, is precisely the area that the
<classname>IObjectWrapper</classname> addresses.</para>
<literal>IObjectWrapper</literal> addresses.</para>
</sect1>
<sect1 id="objects-objects">
<sect1 xml:id="objects-objects">
<title>Manipulating objects using the IObjectWrapper</title>
<para>One quite important concept of the <literal>Spring.Objects</literal>
namespace is encapsulated in the definition
<classname>IObjectWrapper</classname> interface and its corresponding
implementation, the <classname>ObjectWrapper</classname> class. The
functionality offered by the <classname>IObjectWrapper</classname>
<literal>IObjectWrapper</literal> interface and its corresponding
implementation, the <literal>ObjectWrapper</literal> class. The
functionality offered by the <literal>IObjectWrapper</literal>
includes methods to set and get property values (either individually or in
bulk), get property descriptors (instances of the
<classname>System.Reflection.PropertyInfo</classname> class), and to query
<literal>System.Reflection.PropertyInfo</literal> class), and to query
the readability and writability of properties. The
<classname>IObjectWrapper</classname> also offers support for nested
<literal>IObjectWrapper</literal> also offers support for nested
properties, enabling the setting of properties on subproperties to an
unlimited depth. The <classname>IObjectWrapper</classname> usually isn't
unlimited depth. The <literal>IObjectWrapper</literal> usually isn't
used by application code directly, but by framework classes such as the
various <classname>IObjectFactory</classname> implementations.</para>
various <literal>IObjectFactory</literal> implementations.</para>
<para>The way the <classname>IObjectWrapper</classname> works is partly
<para>The way the <literal>IObjectWrapper</literal> works is partly
indicated by its name: <emphasis>it wraps an object</emphasis> to perform
actions on a wrapped object instance... such actions would include the
setting and getting of properties exposed on the wrapped object.</para>
<para><emphasis>Note: the concepts explained in this section are not
important to you if you're not planning to work with the
<classname>IObjectWrapper</classname> directly.</emphasis></para>
<literal>IObjectWrapper</literal> directly.</emphasis></para>
<sect2 id="objects-objects-conventions">
<sect2 xml:id="objects-objects-conventions">
<title>Setting and getting basic and nested properties</title>
<para>Setting and getting properties is done using the
@@ -59,7 +76,7 @@
<methodname>GetPropertyValue()</methodname> methods have a number of
conventions for indicating the path of a property. A property path is an
expression that implementations of the
<classname>IObjectWrapper</classname> interface can use to look up the
<literal>IObjectWrapper</literal> interface can use to look up the
properties of the wrapped object; some examples of property paths
include...</para>
@@ -109,8 +126,8 @@
</table></para>
<para>Below you'll find some examples of working with the
<classname>IObjectWrapper</classname> to get and set properties.
Consider the following two classes: <programlisting>[C#]
<literal>IObjectWrapper</literal> to get and set properties.
Consider the following two classes: <programlisting language="csharp">[C#]
public class Company
{
private string name;
@@ -127,7 +144,7 @@ public class Company
get { return this.managingDirector; }
set { this.managingDirector = value; }
}
}</programlisting> <programlisting>[C#]
}</programlisting> <programlisting language="csharp">[C#]
public class Employee
{
private string name;
@@ -148,8 +165,8 @@ public class Employee
<para>The following code snippets show some examples of how to retrieve
and manipulate some of the properties of
<classname>IObjectWrapper</classname>-wrapped <literal>Company</literal>
and <literal>Employee</literal> instances. <programlisting>[C#]
<literal>IObjectWrapper</literal>-wrapped <literal>Company</literal>
and <literal>Employee</literal> instances. <programlisting language="csharp">[C#]
Company c = new Company();
IObjectWrapper owComp = new ObjectWrapper(c);
// setting the company name...
@@ -177,7 +194,7 @@ float salary = (float)owComp.GetPropertyValue("managingDirector.salary");</progr
identifier. The following example (using the classes defined previously)
should serve to illustrate this...</para>
<programlisting>[C#]
<programlisting language="csharp">[C#]
// ok, let's create the director and bind it to the company...
Employee don = new Employee();
IObjectWrapper owDon = new ObjectWrapper(don);
@@ -197,7 +214,7 @@ Console.WriteLine(don.Salary); // puts 80000</programlisting>
practice.</para>
</sect2>
<sect2 id="objects-objects-other">
<sect2 xml:id="objects-objects-other">
<title>Other features worth mentioning</title>
<para>In addition to the features described in the preceding sections
@@ -214,7 +231,7 @@ Console.WriteLine(don.Salary); // puts 80000</programlisting>
<para><emphasis>retrieving PropertyInfo instances</emphasis>:
using <literal>GetPropertyInfo(string)</literal> and
<literal>GetPropertyInfos()</literal> you can retrieve instances
of the <classname>System.Reflection.PropertyInfo</classname>
of the <literal>System.Reflection.PropertyInfo</literal>
class, that might come in handy sometimes when you need access to
the property metadata specific to the object being wrapped.</para>
</listitem>
@@ -222,19 +239,19 @@ Console.WriteLine(don.Salary); // puts 80000</programlisting>
</sect2>
</sect1>
<sect1 id="objects-objects-conversion">
<sect1 xml:id="objects-objects-conversion">
<title>Type conversion</title>
<para>If you associate a <classname>TypeConverter</classname> with the
definition of a custom <classname>Type</classname> using the standard .NET
<para>If you associate a <literal>TypeConverter</literal> with the
definition of a custom <literal>Type</literal> using the standard .NET
mechanism (see the example code below), Spring.NET will use the associated
<classname>TypeConverter</classname> to do the conversion.<programlisting>[C#]
<literal>TypeConverter</literal> to do the conversion.<programlisting language="csharp">[C#]
[TypeConverter (typeof (FooTypeConverter))]
public class Foo
{
}</programlisting></para>
<para>The <classname>TypeConverter</classname> class from the
<para>The <literal>TypeConverter</literal> class from the
<literal>System.ComponentModel</literal> namespace of the .NET BCL is used
extensively by the various classes in the <literal>Spring.Core</literal>
library, as said class <quote>... provides a unified way of converting
@@ -249,36 +266,36 @@ public class Foo
<para>For example, a date can be represented in a human readable format
(such as <literal>30th August 1984</literal>), while we're still able to
convert the human readable form to the original date format or (even
better) to an instance of the <classname>System.DateTime</classname>
better) to an instance of the <literal>System.DateTime</literal>
class. This behavior can be achieved by using the standard .NET idiom of
decorating a class with the <classname>TypeConverterAttribute</classname>.
decorating a class with the <literal>TypeConverterAttribute</literal>.
Spring.NET also offers another means of associating a
<classname>TypeConverters</classname> with a class. You might want to do
<literal>TypeConverters</literal> with a class. You might want to do
this to achieve a conversion that is not possible using standard idiom...
for example, the <literal>Spring.Core</literal> library contains a custom
<classname>TypeConverter</classname> that converts comma-delimited strings
<literal>TypeConverter</literal> that converts comma-delimited strings
to String array instances. Registering custom converters on an
<classname>IObjectWrapper</classname> instance gives the wrapper the
<literal>IObjectWrapper</literal> instance gives the wrapper the
knowledge of how to convert properties to the desired
<classname>Type</classname>.</para>
<literal>Type</literal>.</para>
<para>An example of where property conversion is used in Spring.NET is the
setting of properties on objects, accomplished using the aforementioned
<literal>TypeConverters</literal>. When mentioning
<classname>System.String</classname> as the value of a property of some
<literal>System.String</literal> as the value of a property of some
object (declared in an XML file for instance), Spring.NET will (if the
type of the associated property is <classname>System.Type</classname>) use
the <classname>RuntimeTypeConverter</classname> class to try to resolve
the property value to a <classname>Type</classname> object. The example
type of the associated property is <literal>System.Type</literal>) use
the <literal>RuntimeTypeConverter</literal> class to try to resolve
the property value to a <literal>Type</literal> object. The example
below demonstrates this automatic conversion of the
<literal>Example.Xml.SAXParser</literal> (a string) into the corresponding
<classname>Type</classname> instance for use in this factory-style class.
<programlisting>&lt;objects xmlns="http://www.springframework.net"&gt;
<literal>Type</literal> instance for use in this factory-style class.
<programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"&gt;
&lt;object id="parserFactory" type="Example.XmlParserFactory, ExamplesLibrary"
destroy-method="Close"&gt;
&lt;property name="ParserClass" value="Example.Xml.SAXParser, ExamplesLibrary"/&gt;
&lt;/object&gt;
&lt;/objects&gt;</programlisting> <programlisting>[C#]
&lt;/objects&gt;</programlisting> <programlisting language="csharp">[C#]
public class XmlParserFactory
{
private Type parserClass;
@@ -295,35 +312,35 @@ public class XmlParserFactory
}
}</programlisting></para>
<sect2 id="objects-misc-enums">
<sect2 xml:id="objects-misc-enums">
<title>Type Conversion for Enumerations</title>
<para>The default type converter for enumerations is the
<classname>System.ComponentModel.EnumConverter</classname> class. To
<literal>System.ComponentModel.EnumConverter</literal> class. To
specify the value for an enumerated property, simply use the name of the
property. For example the <classname>TestObject</classname> class has a
property of the enumerated type <classname>FileMode</classname>. One of
property. For example the <literal>TestObject</literal> class has a
property of the enumerated type <literal>FileMode</literal>. One of
the values for this enumeration is named <literal>Create</literal>. The
following XML fragment shows how to configure this property</para>
<programlisting>&lt;object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests"&gt;
<programlisting language="myxml">&lt;object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests"&gt;
&lt;property name="name" value="Rod"/&gt;
&lt;property name="FileMode" value="Create"/&gt;
&lt;/object&gt;</programlisting>
</sect2>
</sect1>
<sect1 id="object-objects-builtin-converters">
<sect1 xml:id="object-objects-builtin-converters">
<title>Built-in TypeConverters</title>
<para>Spring.NET has a number of built-in
<classname>TypeConverters</classname> to make life easy. Each of those is
<literal>TypeConverters</literal> to make life easy. Each of those is
listed below and they are all located in the
<literal>Spring.Objects.TypeConverters</literal> namespace of the
<literal>Spring.Core</literal> library.</para>
<para><table frame="all">
<title>Built-in <classname>TypeConverters</classname></title>
<title>Built-in <literal>TypeConverters</literal></title>
<tgroup cols="2">
<colspec colname="c1" colwidth="3*" />
@@ -343,8 +360,8 @@ public class XmlParserFactory
<entry><literal>RuntimeTypeConverter</literal></entry>
<entry>Parses strings representing
<classname>System.Types</classname> to actual
<classname>System.Types</classname> and the other way
<literal>System.Types</literal> to actual
<literal>System.Types</literal> and the other way
around.</entry>
</row>
@@ -352,7 +369,7 @@ public class XmlParserFactory
<entry><literal>FileInfoConverter</literal></entry>
<entry>Capable of resolving strings to a
<classname>System.IO.FileInfo</classname> object.</entry>
<literal>System.IO.FileInfo</literal> object.</entry>
</row>
<row>
@@ -396,7 +413,7 @@ public class XmlParserFactory
<entry>Capable of resolving a two part string (resource name,
assembly name) to a
<classname>System.Resources.ResourceManager</classname>
<literal>System.Resources.ResourceManager</literal>
object.</entry>
</row>
@@ -405,7 +422,7 @@ public class XmlParserFactory
<entry>Capable of resolving a comma separated list of Red,
Green, Blue integer values to a
<classname>System.Drawing.Color</classname> structure.</entry>
<literal>System.Drawing.Color</literal> structure.</entry>
</row>
<row>
@@ -419,7 +436,7 @@ public class XmlParserFactory
</table></para>
<para>Spring.NET uses the standard .NET mechanisms for the resolution of
<classname>System.Types</classname>, including, but not limited to
<literal>System.Types</literal>, including, but not limited to
checking any configuration files associated with your application,
checking the Global Assembly Cache (GAC), and assembly probing.</para>

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="orm">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="orm" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Object Relational Mapping (ORM) data access</title>
<section id="orm-introduction">
<section xml:id="orm-introduction">
<title>Introduction</title>
<para>The Spring Framework provides integration with <emphasis>NHibernate
@@ -31,8 +48,8 @@
<listitem>
<para><emphasis>Ease of testing.</emphasis> Spring's IoC approach
makes it easy to swap the implementations and config locations of
Hibernate <interfacename>SessionFactory</interfacename> instances,
ADO.NET <interfacename>DbProvider</interfacename> instances,
Hibernate <literal>SessionFactory</literal> instances,
ADO.NET <literal>DbProvider</literal> instances,
transaction managers, and mapper object implementations (if needed).
This makes it much easier to isolate and test each piece of
persistence-related code in isolation.</para>
@@ -52,18 +69,18 @@
<listitem>
<para><emphasis>General resource management.</emphasis> Spring
application contexts can handle the location and configuration of
Hibernate <interfacename>ISessionFactory</interfacename> instances,
ADO.NET <interfacename>DbProvider</interfacename> instances and other
Hibernate <literal>ISessionFactory</literal> instances,
ADO.NET <literal>DbProvider</literal> instances and other
related resources. This makes these values easy to manage and change.
Spring offers efficient, easy and safe handling of persistence
resources. For example: related code using NHibernate generally needs
to use the same NHibernate <interfacename>Session</interfacename> for
to use the same NHibernate <literal>Session</literal> for
efficiency and proper transaction handling. Spring makes it easy to
transparently create and bind a <interfacename>Session</interfacename>
transparently create and bind a <literal>Session</literal>
to the current thread, either by using an explicit 'template' wrapper
class at the code level or by exposing a current
<interfacename>Session</interfacename> through the Hibernate
<interfacename>SessionFactory</interfacename> (for DAOs based on plain
<literal>Session</literal> through the Hibernate
<literal>SessionFactory</literal> (for DAOs based on plain
Hibernate 1.2 API). Thus Spring solves many of the issues that
repeatedly arise from typical NHibernate usage, for any transaction
environment (local or distributed).</para>
@@ -110,7 +127,7 @@
value proposition.</para>
</section>
<section id="orm-hibernate">
<section xml:id="orm-hibernate">
<title>NHibernate</title>
<para>We will start with a coverage of <ulink
@@ -127,7 +144,7 @@
the 'template' approach. Spring supports both NHibernate 1.0 and
NHibernate 1.2 via separate .dlls with the same internal namespace.</para>
<section id="orm-resource-mngmnt">
<section xml:id="orm-resource-mngmnt">
<title>Resource management</title>
<para>Typical business applications are often cluttered with repetitive
@@ -140,18 +157,18 @@
for appropriate conversion of specific API exceptions to a common
infrastructure exception hierarchy. Spring introduces a DAO exception
hierarchy, applicable to any data access strategy. For direct ADO.NET,
the <classname>AdoTemplate</classname> class mentioned in a previous
the <literal>AdoTemplate</literal> class mentioned in a previous
section cares for connection handling, and for proper conversion of
ADO.NET data access exceptions (not even singly rooted in .NET 1.1) to
Spring's <classname>DataAccessException</classname> hierarchy, including
Spring's <literal>DataAccessException</literal> hierarchy, including
translation of database-specific SQL error codes to meaningful exception
classes. It supports both distributed and local transactions, via
respective Spring transaction managers.</para>
<para>Spring also offers Hibernate support, consisting of a
<classname>HibernateTemplate</classname> analogous to
<classname>AdoTemplate</classname>, a
<classname>HibernateInterceptor</classname>, and a Hibernate transaction
<literal>HibernateTemplate</literal> analogous to
<literal>AdoTemplate</literal>, a
<literal>HibernateInterceptor</literal>, and a Hibernate transaction
manager. The major goal is to allow for clear application layering, with
any data access and transaction technology, and for loose coupling of
application objects. No more business service dependencies on the data
@@ -169,7 +186,7 @@
the business services),and so on.</para>
</section>
<section id="orm-tx-mgmt">
<section xml:id="orm-tx-mgmt">
<title>Transaction Management</title>
<para>While NHibernate offers an API for transaction management you will
@@ -183,8 +200,8 @@
the other the .NET 2.0 TransactionScope API.</para>
<para>The first strategy is encapsulated in the class
<classname>Spring.Data.NHibernate.HibernateTransactionManager
</classname>in both the <literal>Spring.Data.NHibernate
<literal>Spring.Data.NHibernate.HibernateTransactionManager
</literal>in both the <literal>Spring.Data.NHibernate
</literal>namespace. This strategy is preferred when you are using a
single database. ADO.NET operations can also participate in the same
transaction, either by using AdoTemplate or by retrieving the ADO.NET
@@ -198,10 +215,10 @@
configuration file to gain the benefits of easy configuration for a
particular runtime environment and as the basis for the configuration of
a data access layer also configured using XML. An XML fragment showing
the declaration of <classname>HibernateTransactionManager</classname> is
the declaration of <literal>HibernateTransactionManager</literal> is
shown below.</para>
<programlisting> &lt;object id="HibernateTransactionManager"
<programlisting language="myxml"> &lt;object id="HibernateTransactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate"&gt;
&lt;property name="DbProvider" ref="DbProvider"/&gt;
@@ -210,14 +227,14 @@
&lt;/object&gt;</programlisting>
<para>The important property of
<classname>HibernateTransactionManager</classname> are the references to
<literal>HibernateTransactionManager</literal> are the references to
the DbProvider and the Hibernate ISessionFactory. For more information
on the DbProvider, refer to the chapter <link
linkend="dbprovider">DbProvider</link> and the following section on
SessionFactory set up.</para>
<para>The second strategy is to use the class
<classname>Sping.Data.TxScopeTransactionManager</classname> that uses
<literal>Sping.Data.TxScopeTransactionManager</literal> that uses
.NET 2.0 System.Transaction namespace and its corresponding
TransactionScope API. This is preferred when you are using multiple
transactional resources, such as multiple databases.</para>
@@ -226,7 +243,7 @@
the transaction (scope in the general demarcation sense, not
System.Transaction sense). If there is no transaction then a new Session
will be opened for each operation. The exception to this rule is when
using the <classname>OpenSessionInViewModule</classname> in a web
using the <literal>OpenSessionInViewModule</literal> in a web
application in single session mode (see <xref
linkend="orm-hibernate-web" />). In this case the session will be
created on the start of the web request and closed on the end of the
@@ -240,22 +257,22 @@
of the web request.</para>
</section>
<section id="orm-session-factory-setup">
<title><interfacename>SessionFactory</interfacename> set up in a Spring
<section xml:id="orm-session-factory-setup">
<title><literal>SessionFactory</literal> set up in a Spring
container</title>
<para>To avoid tying application objects to hard-coded resource lookups,
Spring allows you to define resources like a
<interfacename>DbProvider</interfacename> or a Hibernate
<interfacename>SessionFactory</interfacename> as objects in an
<literal>DbProvider</literal> or a Hibernate
<literal>SessionFactory</literal> as objects in an
application context. Application objects that need to access resources
just receive references to such pre-defined instances via object
references (the DAO definition in the next section illustrates this).
The following excerpt from an XML application context definition shows
how to set up Spring's ADO.NET DbProvider and a Hibernate
<interfacename>SessionFactory</interfacename> on top of it:</para>
<literal>SessionFactory</literal> on top of it:</para>
<programlisting>&lt;objects xmlns="http://www.springframework.net"
<programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"
xmlns:db="http://www.springframework.net/database"&gt;
@@ -318,7 +335,7 @@
array so multiple configuration files are supported.</para>
<para>There are other properties in
<classname>LocalSessionFactoryObject</classname> that relate to the
<literal>LocalSessionFactoryObject</literal> that relate to the
integration of Spring with NHibernate. The property
<literal>ExposeTransactionAwareSessionFactory</literal> is discussed
below and allows you to use Spring's declarative transaction demarcation
@@ -335,7 +352,7 @@
</listitem>
<listitem>
<para>Delegate to the <classname>DbProvider</classname> itself as
<para>Delegate to the <literal>DbProvider</literal> itself as
the NHibernate connection provider instead of listing it via
property hibernate.connection.provider via
<literal>HibernateProperties</literal>.</para>
@@ -345,9 +362,9 @@
<para>If you specify both the property hibernate.connection.provider and
DbProvider (as shown above) the configuration of the property
hibernate.connection.provider is used and a warning level message is
logged. If you use Spring's <classname>DbProvider</classname> as the
logged. If you use Spring's <literal>DbProvider</literal> as the
NHibernate connection provider then you can take advantage of
<classname>IDbProvider</classname> implementations that will let you
<literal>IDbProvider</literal> implementations that will let you
change the connection string at runtime such as <link lang=""
linkend="dbprovider-usercredentials">UserCredentialsDbProvider</link>
and <link
@@ -360,39 +377,39 @@
linkend="dbprovider-multidelegating">MultiDelegatingDbProvider</link>
only change the connection string at runtime based on values in thread
local storage and do not clear out the Hibernate cache that is unique
to each <classname>ISessionFactory</classname> instance. As such, they
to each <literal>ISessionFactory</literal> instance. As such, they
are only useful for selecting at runtime a single database instance.
Cleaning up an existing session factory when switching to a new
database is left to user code. Creating a new session factory per
connection string (assuming the same mapping files can be used across
all databases connections) is not currently supported. To support this
functionality, you can subclass
<classname>LocalSessionFactoryObject</classname> and override the
<literal>LocalSessionFactoryObject</literal> and override the
method <literal>ISessionFactory NewSessionFactory(Configuration
config)</literal> so that it returns an implementation of
<classname>ISessionFactory</classname> that selects among multiple
<literal>ISessionFactory</literal> that selects among multiple
instances based on values in thread local storage, much like the
implementation of
<classname>MultiDelegatingDbProvider</classname>.</para>
<literal>MultiDelegatingDbProvider</literal>.</para>
</note>
</section>
<section id="orm-hibernate-template">
<title>The <classname>HibernateTemplate</classname></title>
<section xml:id="orm-hibernate-template">
<title>The <literal>HibernateTemplate</literal></title>
<para>The basic programming model for templating looks as follows for
methods that can be part of any custom data access object or business
service. There are no restrictions on the implementation of the
surrounding object at all, it just needs to provide a Hibernate
<interfacename>SessionFactory</interfacename>. It can get the latter
<literal>SessionFactory</literal>. It can get the latter
from anywhere, but preferably as an object reference from a Spring IoC
container - via a simple <methodname>SessionFactory</methodname>
property setter. The following snippets show a DAO definition in a
Spring container, referencing the above defined
<interfacename>SessionFactory</interfacename>, and an example for a DAO
<literal>SessionFactory</literal>, and an example for a DAO
method implementation.</para>
<programlisting>&lt;objects&gt;
<programlisting language="myxml">&lt;objects&gt;
&lt;object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate"&gt;
&lt;property name="SessionFactory" ref="MySessionFactory"/&gt;
@@ -402,7 +419,7 @@
<para></para>
<programlisting>public class HibernateCustomerDao : ICustomerDao {
<programlisting language="csharp">public class HibernateCustomerDao : ICustomerDao {
private HibernateTemplate hibernateTemplate;
@@ -418,15 +435,15 @@
}
}</programlisting>
<para>The <classname>HibernateTemplate</classname> class provides many
<para>The <literal>HibernateTemplate</literal> class provides many
methods that mirror the methods exposed on the Hibernate
<interfacename>Session</interfacename> interface, in addition to a
<literal>Session</literal> interface, in addition to a
number of convenience methods such as the one shown above. If you need
access to the <interfacename>Session</interfacename> to invoke methods
that are not exposed on the <classname>HibernateTemplate</classname>,
access to the <literal>Session</literal> to invoke methods
that are not exposed on the <literal>HibernateTemplate</literal>,
you can always drop down to a callback-based approach like so.</para>
<programlisting>public class HibernateCustomerDao : ICustomerDao {
<programlisting language="csharp">public class HibernateCustomerDao : ICustomerDao {
private HibernateTemplate hibernateTemplate;
@@ -454,7 +471,7 @@
generics, you can avoid the typecast and write code like the
following</para>
<programlisting>IList&lt;Supplier&gt; suppliers = HibernateTemplate.ExecuteFind&lt;Supplier&gt;(
<programlisting language="csharp">IList&lt;Supplier&gt; suppliers = HibernateTemplate.ExecuteFind&lt;Supplier&gt;(
delegate(ISession session)
{
return session.CreateQuery("from Supplier s were s.Code = ?")
@@ -466,22 +483,22 @@
inside the anonymous delegate implementation.</para>
<para>A callback implementation effectively can be used for any
Hibernate data access. <classname>HibernateTemplate</classname> will
ensure that <interfacename>Session</interfacename> instances are
Hibernate data access. <literal>HibernateTemplate</literal> will
ensure that <literal>Session</literal> instances are
properly opened and closed, and automatically participate in
transactions. The template instances are thread-safe and reusable, they
can thus be kept as instance variables of the surrounding class. For
simple single step actions like a single Find, Load, SaveOrUpdate, or
Delete call, <classname>HibernateTemplate</classname> offers alternative
Delete call, <literal>HibernateTemplate</literal> offers alternative
convenience methods that can replace such one line callback
implementations. Furthermore, Spring provides a convenient
<classname>HibernateDaoSupport</classname> base class that provides a
<literal>HibernateDaoSupport</literal> base class that provides a
<methodname>SessionFactory</methodname> property for receiving a
<interfacename>SessionFactory</interfacename> and for use by subclasses.
<literal>SessionFactory</literal> and for use by subclasses.
In combination, this allows for very simple DAO implementations for
typical requirements:</para>
<programlisting>public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao
<programlisting language="csharp">public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao
{
public Customer SaveOrUpdate(Customer customer)
{
@@ -491,28 +508,28 @@
}</programlisting>
</section>
<section id="orm-hibernate-daos">
<section xml:id="orm-hibernate-daos">
<title>Implementing Spring-based DAOs without callbacks</title>
<para>As an alternative to using Spring's
<classname>HibernateTemplate</classname> to implement DAOs, data access
<literal>HibernateTemplate</literal> to implement DAOs, data access
code can also be written in a more traditional fashion, without wrapping
the Hibernate access code in a callback, while still respecting and
participating in Spring's generic
<classname>DataAccessException</classname> hierarchy. The
<classname>HibernateDaoSupport</classname> base class offers methods to
access the current transactional <interfacename>Session</interfacename>
<literal>DataAccessException</literal> hierarchy. The
<literal>HibernateDaoSupport</literal> base class offers methods to
access the current transactional <literal>Session</literal>
and to convert exceptions in such a scenario; similar methods are also
available as static helpers on the
<classname>SessionFactoryUtils</classname> class. Note that such code
<literal>SessionFactoryUtils</literal> class. Note that such code
will usually pass '<literal>false</literal>' as the value of the
<methodname>DoGetSession(..)</methodname> method's
'<literal>allowCreate</literal>' argument, to enforce running within a
transaction (which avoids the need to close the returned
<interfacename>Session</interfacename>, as its lifecycle is managed by
<literal>Session</literal>, as its lifecycle is managed by
the transaction). Asking for the</para>
<programlisting>public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {
<programlisting language="csharp">public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {
public Customer SaveOrUpdate(Customer customer)
{
@@ -527,18 +544,18 @@
DataAccessException.</para>
</section>
<section id="orm-hibernate-straight">
<section xml:id="orm-hibernate-straight">
<title>Implementing DAOs based on plain Hibernate 1.2 API</title>
<para>Hibernate 1.2 introduced a feature called "contextual Sessions",
where Hibernate itself manages one current
<interfacename>ISession</interfacename> per transaction. This is roughly
<literal>ISession</literal> per transaction. This is roughly
equivalent to Spring's synchronization of one Hibernate
<interfacename>Session</interfacename> per transaction. A corresponding
<literal>Session</literal> per transaction. A corresponding
DAO implementation looks like as follows, based on the plain Hibernate
API:</para>
<programlisting>public class ProductDaoImpl implements IProductDao {
<programlisting language="csharp">public class ProductDaoImpl implements IProductDao {
private SessionFactory sessionFactory;
@@ -575,13 +592,13 @@ public class HibernateCustomerDao : ICustomerDao {
<para>The above DAO follows the Dependency Injection pattern: it fits
nicely into a Spring IoC container, just like it would if coded against
Spring's <classname>HibernateTemplate</classname>. Of course, such a DAO
Spring's <literal>HibernateTemplate</literal>. Of course, such a DAO
can also be set up in plain C# (for example, in unit tests): simply
instantiate it and call <methodname>SessionFactory</methodname> property
with the desired factory reference. As a Spring object definition, it
would look as follows:</para>
<programlisting>
<programlisting language="myxml">
&lt;objects&gt;
&lt;object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate"&gt;
@@ -602,9 +619,9 @@ public class HibernateCustomerDao : ICustomerDao {
<para>The first way is shown below</para>
<programlisting>&lt;object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12"&gt;
<programlisting language="myxml">&lt;object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12"&gt;
<emphasis role="bold">&lt;property name="ExposeTransactionAwareSessionFactory" value="true" /&gt;</emphasis>
&lt;property name="ExposeTransactionAwareSessionFactory" value="true" /&gt;
&lt;!-- other configuration settings omitted --&gt;
@@ -612,7 +629,7 @@ public class HibernateCustomerDao : ICustomerDao {
<para>Which is simply a shortcut for the following configuration</para>
<programlisting>&lt;object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12"&gt;
<programlisting language="myxml">&lt;object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12"&gt;
&lt;!-- other configuration settings omitted --&gt;
@@ -621,8 +638,8 @@ public class HibernateCustomerDao : ICustomerDao {
&lt;!-- other dictionary entries omitted --&gt;
<emphasis role="bold">&lt;entry key="hibernate.current_session_context_class"
value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12"/&gt;</emphasis>
&lt;entry key="hibernate.current_session_context_class"
value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12"/&gt;
&lt;/dictionary&gt;
&lt;/property&gt;
@@ -635,7 +652,7 @@ public class HibernateCustomerDao : ICustomerDao {
doubt feel more natural to Hibernate developers.</para>
<para>However, the DAO throws plain
<classname>HibernateException</classname> which means that callers can
<literal>HibernateException</literal> which means that callers can
only treat exceptions as generally fatal - unless they want to depend on
Hibernate's own exception hierarchy. Catching specific causes such as an
optimistic locking failure is not possible without tying the caller to
@@ -644,11 +661,11 @@ public class HibernateCustomerDao : ICustomerDao {
special exception treatment.</para>
<para>Fortunately, Spring's
<classname>LocalSessionFactoryObject</classname> supports Hibernate's
<literal>LocalSessionFactoryObject</literal> supports Hibernate's
<methodname>SessionFactory.GetCurrentSession()</methodname> method for
any Spring transaction strategy, returning the current Spring-managed
transactional <interfacename>Session</interfacename> even with
<classname>HibernateTransactionManager</classname>.</para>
transactional <literal>Session</literal> even with
<literal>HibernateTransactionManager</literal>.</para>
<para>In summary: DAOs can be implemented based on the plain Hibernate
1.2 API, while still being able to participate in Spring-managed
@@ -656,29 +673,29 @@ public class HibernateCustomerDao : ICustomerDao {
transaction.</para>
</section>
<section id="orm-hibernate-tx-programmatic">
<section xml:id="orm-hibernate-tx-programmatic">
<title>Programmatic transaction demarcation</title>
<para>Transactions can be demarcated in a higher level of the
application, on top of such lower-level data access services spanning
any number of operations. There are no restrictions on the
implementation of the surrounding business service here as well, it just
needs a Spring <classname>PlatformTransactionManager</classname>. Again,
needs a Spring <literal>PlatformTransactionManager</literal>. Again,
the latter can come from anywhere, but preferably as an object reference
via a <methodname>TransactionManager</methodname> property - just like
the <classname>productDAO</classname> should be set via a
the <literal>productDAO</literal> should be set via a
<methodname>setProductDao(..)</methodname> method. The following
snippets show a transaction manager and a business service definition in
a Spring application context, and an example for a business method
implementation.</para>
<programlisting>&lt;objects&gt;
<programlisting language="myxml">&lt;objects&gt;
TO BE DONE
&lt;/objects&gt;</programlisting>
<programlisting>public class FulfillmentService : IFulfillmentService
<programlisting language="csharp">public class FulfillmentService : IFulfillmentService
private TransactionTemplate transactionTemplate;
@@ -697,7 +714,7 @@ TO BE DONE
}</programlisting>
</section>
<section id="orm-hibernate-tx-declarative">
<section xml:id="orm-hibernate-tx-declarative">
<title>Declarative transaction demarcation</title>
<para>Alternatively, one can use Spring's declarative transaction
@@ -711,7 +728,7 @@ TO BE DONE
<para>An example showing attribute driven transaction is shown
below</para>
<programlisting>&lt;objects&gt;
<programlisting language="myxml">&lt;objects&gt;
&lt;object id="HibernateTransactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate"&gt;
@@ -740,7 +757,7 @@ TO BE DONE
expresses the intent as compared to the contents of
DeclarativeServicesAttributeDriven.xml.</para>
<programlisting>&lt;objects xmlns="http://www.springframework.net"
<programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.net/schema/tx"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/schema/objects/spring-objects.xsd
@@ -772,7 +789,7 @@ TO BE DONE
<para>The placement of the transaction attribute in the service layer
method is shown below.</para>
<programlisting>public class FulfillmentService : IFulfillmentService
<programlisting language="csharp">public class FulfillmentService : IFulfillmentService
{
// fields and properties for dao object omitted, see above
@@ -808,7 +825,7 @@ TO BE DONE
boundaries, you can import a configuration file with the following XML
instead of using &lt;tx:attribute-driven/&gt;</para>
<programlisting> &lt;object id="TxProxyConfigurationTemplate" abstract="true"
<programlisting language="myxml"> &lt;object id="TxProxyConfigurationTemplate" abstract="true"
type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data"&gt;
&lt;property name="PlatformTransactionManager" ref="HibernateTransactionManager"/&gt;
@@ -825,23 +842,23 @@ TO BE DONE
configuration of other features, such as rollback rules.</para>
</section>
<section id="orm-hibernate-tx-strategies">
<section xml:id="orm-hibernate-tx-strategies">
<title>Transaction management strategies</title>
<para>Both <classname>TransactionTemplate</classname> and
<classname>TransactionInterceptor</classname> (not yet seen explicitly
<para>Both <literal>TransactionTemplate</literal> and
<literal>TransactionInterceptor</literal> (not yet seen explicitly
in above configuration, TransactionProxyFactoryObject uses a
TransactionInterceptor, you would have to specify it explicitly if you
were using an ordinary ProxyFactoryObject.) delegate the actual
transaction handling to a
<classname>PlatformTransactionManager</classname> instance, which can be
a <classname>HibernateTransactionManager</classname> (for a single
Hibernate <interfacename>SessionFactory</interfacename>, using a
<classname>ThreadLocal</classname>
<interfacename>Session</interfacename> under the hood) or a
<classname>TxScopeTransactionManager</classname> (delegating to MS-DTC
<literal>PlatformTransactionManager</literal> instance, which can be
a <literal>HibernateTransactionManager</literal> (for a single
Hibernate <literal>SessionFactory</literal>, using a
<literal>ThreadLocal</literal>
<literal>Session</literal> under the hood) or a
<literal>TxScopeTransactionManager</literal> (delegating to MS-DTC
for distributed transaction) for Hibernate applications. You could even
use a custom <classname>PlatformTransactionManager</classname>
use a custom <literal>PlatformTransactionManager</literal>
implementation. So switching from native Hibernate transaction
management to TxScopeTransactionManager, such as when facing distributed
transaction requirements for certain deployments of your application, is
@@ -852,24 +869,24 @@ TO BE DONE
<para>For distributed transactions across multiple Hibernate session
factories, simply combine
<classname>TxScopeTransactionManager</classname> as a transaction
strategy with multiple <classname>LocalSessionFactoryObject</classname>
<literal>TxScopeTransactionManager</literal> as a transaction
strategy with multiple <literal>LocalSessionFactoryObject</literal>
definitions. Each of your DAOs then gets one specific
<interfacename>SessionFactory</interfacename> reference passed into it's
<literal>SessionFactory</literal> reference passed into it's
respective object property.</para>
<programlisting>TO BE DONE
</programlisting>
<para><classname>HibernateTransactionManager</classname> can export the
ADO.NET <interfacename>Transaction</interfacename> used by Hibernate to
<para><literal>HibernateTransactionManager</literal> can export the
ADO.NET <literal>Transaction</literal> used by Hibernate to
plain ADO.NET access code, for a specific
<interfacename>DbProvider</interfacename>. (matching connection string).
<literal>DbProvider</literal>. (matching connection string).
This allows for high-level transaction demarcation with mixed
Hibernate/ADO.NET data access!</para>
</section>
<section id="orm-hibernate-web">
<section xml:id="orm-hibernate-web">
<title>Web Session Management</title>
<para>The open session in view pattern keeps the hibernate session open
@@ -877,7 +894,7 @@ TO BE DONE
displayed. You configure its use by adding an additional custom HTTP
module declaration as shown below</para>
<programlisting> &lt;system.web&gt;
<programlisting language="myxml"> &lt;system.web&gt;
&lt;httpModules&gt;
&lt;add name="OpenSessionInView" type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, Spring.Data.NHibernate"/&gt;
&lt;/httpModules&gt;
@@ -890,7 +907,7 @@ TO BE DONE
will use by setting 'global' application key-value pairs as shown below.
(this will change in future releases)</para>
<programlisting> &lt;appSettings&gt;
<programlisting language="myxml"> &lt;appSettings&gt;
&lt;add key="Spring.Data.NHibernate.Support.OpenSessionInViewModule.SessionFactoryObjectName" value="SessionFactory"/&gt;
&lt;/appSettings&gt;</programlisting>
@@ -933,7 +950,7 @@ TO BE DONE
you to use a single NHibernate session across multiple transactions. The
usage is shown below</para>
<programlisting>using (new SessionScope())
<programlisting language="csharp">using (new SessionScope())
{
... do multiple operations with a single session, possibly in multiple transactions.
}</programlisting>

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="introduction">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="introduction" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Introduction</title>
<sect1 id="introduction-overview">
<sect1 xml:id="introduction-overview">
<title>Overview</title>
<para>Spring.NET is an application framework that provides comprehensive
@@ -79,11 +96,12 @@
started to use the term Dependency Injection. His article then continued
to explain the ideas underpinning the Inversion of Control (IoC) and
Dependency Injection (DI) principle. If you need a decent insight into IoC
and DI, please do refer to the article :
http://martinfowler.com/articles/injection.html.</para>
and DI, please do refer to the article :
<ulink url="http://martinfowler.com/articles/injection.html">
http://martinfowler.com/articles/injection.html</ulink>.</para>
</sect1>
<sect1 id="intro-modules">
<sect1 xml:id="intro-modules">
<title>Modules</title>
<para>The Spring Framework contains a lot of features, which are
@@ -111,7 +129,7 @@
logging, performance monitoring, caching, method retry, and exception
handling.</para>
<para><link linkend="index-middle-tier">Spring.Data</link> - Use this
<para><link linkend="spring-middle-tier">Spring.Data</link> - Use this
module to achieve greater efficiency and consistency in writing data
access functionality in ADO.NET and to perform declarative transaction
management.</para>
@@ -133,7 +151,7 @@
data binding, validation, and ASP.NET page/control/module/provider
configuration.</para>
<para><link linkend="index-services">Spring.Services</link> - Use this
<para><link linkend="spring-services">Spring.Services</link> - Use this
module to adapt plain .NET objects so they can be used with a specific
distributed communication technology, such as .NET Remoting, Enterprise
Services, and ASMX Web Services. These services can be configured via
@@ -296,10 +314,10 @@
scheduling.</para>
</listitem>
<listitem>
<!--<listitem>
<para><link lang="" linkend="msmq-quickstart">MSMQ</link> -
Application demonstrating MSMQ helper classes.</para>
</listitem>
</listitem>-->
<listitem>
<para><link linkend="nms-quickstart">NMS</link> - Applicatoin

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="pool">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="pool" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Object Pooling</title>
<sect1 id="pool-introduction">
<sect1 xml:id="pool-introduction">
<title>Introduction</title>
<para>The Spring.Pool namespace contains a generic API for implementing
@@ -37,7 +54,7 @@
<para>Note, that if you are concerned only with applying pooling to an
existing object, the pooling APIs discussed here are not very important.
Instead the use and configuration of
<classname>Spring.Aop.Target.SimplePoolTargetSource</classname> is more
<literal>Spring.Aop.Target.SimplePoolTargetSource</literal> is more
relevant. Pooling of objects can either be done Programatically or through
the XML configuration of the Spring .NET container. Attribute support for
pooling, similar to the ServicedComponent approach, will be available in a
@@ -47,21 +64,21 @@
use of the pooling API independent of AOP functionality.</para>
</sect1>
<sect1 id="pool-api">
<sect1 xml:id="pool-api">
<title>Interfaces and Implementations</title>
<para>The <literal>Spring.Pool</literal> namespace provides two simple
interfaces to manage pools of objects. The first interface,
<classname>IObjectPool</classname> describes how to take and put back an
<literal>IObjectPool</literal> describes how to take and put back an
object from the pool. The second interface
<classname>IPoolableObjectFactory</classname> is meant to be used in
conjunction with implementations of the <classname>IObjectPool</classname>
<literal>IPoolableObjectFactory</literal> is meant to be used in
conjunction with implementations of the <literal>IObjectPool</literal>
to provide guidance in calling various lifecycle events on the objects
managed by the pool. These interfaces are based on the Jakarta Commons
Pool API. <classname>Spring.Pool.Support.SimplePool</classname> is a
default implementation of <classname>IObjectPool</classname> and
<classname>Spring.Aop.Target.SimplePoolTargetSource</classname> is the
implementation of <classname>IPoolableObjectFactory</classname> for use
Pool API. <literal>Spring.Pool.Support.SimplePool</literal> is a
default implementation of <literal>IObjectPool</literal> and
<literal>Spring.Aop.Target.SimplePoolTargetSource</literal> is the
implementation of <literal>IPoolableObjectFactory</literal> for use
with AOP. The current goal of the Spring.Pool namespace is not to provide
a one-for-one replacement of the Jakarta Commons Pool API, but rather to
support basic object pooling needs for common AOP scenarios. Consequently,

View File

@@ -60,12 +60,10 @@
<para>
In our case, as already said, we want to to implement a pool
of <literal>QueuedExecutor</literal>. Ok, here the declaration:
<programlisting format='linespecific' xml:space='preserve'>
public class QueuedExecutorPoolableFactory : IPoolableObjectFactory
<programlisting language="csharp">public class QueuedExecutorPoolableFactory : IPoolableObjectFactory
{</programlisting>
the first task a factory should do is to create objects:
<programlisting format='linespecific' xml:space='preserve'>
object IPoolableObjectFactory.MakeObject()
<programlisting language="csharp">object IPoolableObjectFactory.MakeObject()
{
// to actually make this work as a pooled executor
// use a bounded queue of capacity 1.
@@ -76,8 +74,7 @@ object IPoolableObjectFactory.MakeObject()
return new QueuedExecutor(new BoundedBuffer(1));
}</programlisting>
and should be also able to destroy them:
<programlisting format='linespecific' xml:space='preserve'>
void IPoolableObjectFactory.DestroyObject(object o)
<programlisting language="csharp">void IPoolableObjectFactory.DestroyObject(object o)
{
// ah, self documenting code:
// Here you can see that we decided to let the
@@ -90,8 +87,7 @@ void IPoolableObjectFactory.DestroyObject(object o)
When an object is taken from the pool, to satisfy a client request,
may be the object should be activated. We can possibly implement the
activation like this:
<programlisting format='linespecific' xml:space='preserve'>
void IPoolableObjectFactory.ActivateObject(object o)
<programlisting language="csharp">void IPoolableObjectFactory.ActivateObject(object o)
{
QueuedExecutor executor = o as QueuedExecutor;
executor.Restart();
@@ -113,8 +109,7 @@ void IPoolableObjectFactory.ActivateObject(object o)
</para>
</footnote>).
Here we check that the worker thread exists:
<programlisting format='linespecific' xml:space='preserve'>
bool IPoolableObjectFactory.ValidateObject(object o)
<programlisting language="csharp">bool IPoolableObjectFactory.ValidateObject(object o)
{
QueuedExecutor executor = o as QueuedExecutor;
return executor.Thread != null;
@@ -124,16 +119,14 @@ bool IPoolableObjectFactory.ValidateObject(object o)
Passivation, symmetrical to activation, is the process a pooled
object is subject to when the object is returned to the pool. In our
case we simply do nothing:
<programlisting format='linespecific' xml:space='preserve'>
void IPoolableObjectFactory.PassivateObject(object o)
<programlisting language="csharp">void IPoolableObjectFactory.PassivateObject(object o)
{
}</programlisting>
</para>
<para>
At this point, creating a pool is simply a matter of creating an
<literal>SimplePool</literal> as in:
<programlisting format='linespecific' xml:space='preserve'>
pool = new SimplePool(new QueuedExecutorPoolableFactory(), size);</programlisting>
<programlisting language="csharp">pool = new SimplePool(new QueuedExecutorPoolableFactory(), size);</programlisting>
</para>
</sect2>
<sect2>
@@ -143,8 +136,7 @@ pool = new SimplePool(new QueuedExecutorPoolableFactory(), size);</programlistin
to be very important in these <literal>c#</literal> days, so we
implement a very simple helper (<literal>PooledObjectHolder</literal>)
that can allow us to do things like:
<programlisting format='linespecific' xml:space='preserve'>
using (PooledObjectHolder holder = PooledObjectHolder.UseFrom(pool))
<programlisting language="csharp">using (PooledObjectHolder holder = PooledObjectHolder.UseFrom(pool))
{
QueuedExecutor executor = (QueuedExecutor) holder.Pooled;
executor.Execute(runnable);
@@ -154,8 +146,7 @@ using (PooledObjectHolder holder = PooledObjectHolder.UseFrom(pool))
</para>
<para>
Here is the implementation:
<programlisting format='linespecific' xml:space='preserve'>
public class PooledObjectHolder : IDisposable
<programlisting language="csharp">public class PooledObjectHolder : IDisposable
{
IObjectPool pool;
object pooled;
@@ -204,8 +195,7 @@ public class PooledObjectHolder : IDisposable
Please don't forget to destroy all the pooled istances once you have
finished! How? Well using something like this in
<literal>PooledQueuedExecutor</literal>:
<programlisting format='linespecific' xml:space='preserve'>
public void Stop ()
<programlisting language="csharp">public void Stop ()
{
// waits for all the grep-task to have been queued ...
foreach (ISync sync in syncs)
@@ -221,8 +211,7 @@ public void Stop ()
<para>
The use of the just built executor is quite straigtforward but a
little tricky if we want to really exploit the pool.
<programlisting format='linespecific' xml:space='preserve'>
private PooledQueuedExecutor executor;
<programlisting language="csharp">private PooledQueuedExecutor executor;
public ParallelGrep(int size)
{
@@ -246,9 +235,8 @@ public void Stop()
executor.Stop();
}</programlisting>
</para>
<para>
<programlisting format='linespecific' xml:space='preserve'>
public static void Main(string[] args)
<para>
<programlisting language="csharp">public static void Main(string[] args)
{
if (args.Length &lt; 3)
{

View File

@@ -1,5 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="preface">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="preface" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Preface</title>
<para>Developing software applications is hard enough even with good tools

View File

@@ -1,5 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="psa-intro">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="psa-intro" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Introduction to Spring Services</title>
<sect1>

View File

@@ -1,5 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="quartz-quickstart">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="quartz-quickstart" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Quartz QuickStart</title>
<section>
@@ -21,22 +38,22 @@
<para>The full details of Quartz are outside the scope of this quickstart
but here is 'quick tour for the impatient' of the main classes and
interfaces used in Quartz so you can get your sea legs. A Quartz
<classname>IJob</classname> interface represents the task you would like
<literal>IJob</literal> interface represents the task you would like
to execute. You either directly implement Quartz's
<classname>IJob</classname> interface or a convenience base class. The
Quartz <classname>Trigger</classname> controls when a job is executed, for
<literal>IJob</literal> interface or a convenience base class. The
Quartz <literal>Trigger</literal> controls when a job is executed, for
example in the wee hours of the morning every weekday . This would be done
using Quartz's <classname>CronTrigger</classname> implementation.
using Quartz's <literal>CronTrigger</literal> implementation.
Instances of your job are created every time the trigger fires. As such,
in order to pass information between different job instances you stash
data away in a hashtable that gets passed to the each Job instance upon
its creation. Quartz's <classname>JobDetail</classname> class combines the
<classname>IJob</classname> and this hashtable of data. Instead of the
standard <classname>System.Collections.Hashtable</classname> the class
<classname>JobDataMap</classname> is used. Triggers are registered with a
Quartz <classname>IScheduler</classname> implementation that manages the
its creation. Quartz's <literal>JobDetail</literal> class combines the
<literal>IJob</literal> and this hashtable of data. Instead of the
standard <literal>System.Collections.Hashtable</literal> the class
<literal>JobDataMap</literal> is used. Triggers are registered with a
Quartz <literal>IScheduler</literal> implementation that manages the
overall execution of the triggers and jobs. The
<classname>StdSchedulerFactory</classname> implementation is generally
<literal>StdSchedulerFactory</literal> implementation is generally
used.</para>
</section>
@@ -44,7 +61,7 @@
<title>Application Overview</title>
<para>The sample application has two types of Jobs. One that inherits from
Spring's convenience base class <classname>QuartzJobObject</classname> and
Spring's convenience base class <literal>QuartzJobObject</literal> and
another which does not inherit from any base class. The latter class is
adapted by Spring to be a Job. Two triggers, one for each of the jobs, are
created. These triggers are in turn registered with a scheduler. In each
@@ -55,13 +72,13 @@
<section>
<title>Standard job scheduling</title>
<para>The Spring base class <classname>QuartzJobObject</classname>
implements <classname>IJob</classname> and allows for your object's
<para>The Spring base class <literal>QuartzJobObject</literal>
implements <literal>IJob</literal> and allows for your object's
properties to be set via values that are stored inside Quartz's
<classname>JobDataMap</classname> that is passed along each time your job
<literal>JobDataMap</literal> that is passed along each time your job
is instantiated due a trigger firing. This class is shown below</para>
<programlisting> public class ExampleJob : QuartzJobObject
<programlisting language="csharp"> public class ExampleJob : QuartzJobObject
{
private string userName;
@@ -79,16 +96,16 @@
}</programlisting>
<para>The method <classname>ExecuteInternal</classname> is called when the
<para>The method <literal>ExecuteInternal</literal> is called when the
trigger fires and is where you would put your business logic. The
<classname>JobExecutionContext</classname> passed in lets you access
<literal>JobExecutionContext</literal> passed in lets you access
various pieces of information about the current job execution, such as the
JobDataMap or information on when the next time the trigger will fire. The
<classname>ExampleJob</classname> is configured by creating a
<classname>JobDetail</classname> object as shown below in the following
<literal>ExampleJob</literal> is configured by creating a
<literal>JobDetail</literal> object as shown below in the following
XML snippet taken from spring-objects.xml</para>
<programlisting> &lt;object name="exampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz"&gt;
<programlisting language="myxml"> &lt;object name="exampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="JobType" value="Spring.Scheduling.Quartz.Example.ExampleJob, Spring.Scheduling.Quartz.Example" /&gt;
&lt;!-- We can inject values through JobDataMap --&gt;
&lt;property name="JobDataAsMap"&gt;
@@ -99,18 +116,18 @@
&lt;/object&gt;</programlisting>
<para>The dictionary property of the
<classname>JobDetailObject</classname>,
<classname>JobDataAsMap</classname>, is used to set the values of the
<literal>JobDetailObject</literal>,
<literal>JobDataAsMap</literal>, is used to set the values of the
ExampleJob's properties. This will result in the ExampleJob being
instantiated with it's UserName property value set to 'Alexandre' the
first time the trigger fires.</para>
<para>We then will schedule this job to be executed on 20 second
increments of every minute as shown below using Spring's
<classname>CronTriggerObject</classname> which creates a Quartz
<literal>CronTriggerObject</literal> which creates a Quartz
CronTrigger.</para>
<programlisting> &lt;object id="cronTrigger" type="Spring.Scheduling.Quartz.CronTriggerObject, Spring.Scheduling.Quartz"&gt;
<programlisting language="myxml"> &lt;object id="cronTrigger" type="Spring.Scheduling.Quartz.CronTriggerObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="jobDetail" ref="exampleJob" /&gt;
&lt;!-- run every 20 second of minute --&gt;
&lt;property name="cronExpressionString" value="0/20 * * * * ?" /&gt;
@@ -119,7 +136,7 @@
<para>Lastly, we schedule this trigger with the scheduler as shown
below</para>
<programlisting> &lt;object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz"&gt;
<programlisting language="myxml"> &lt;object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="triggers"&gt;
&lt;list&gt;
&lt;ref object="cronTrigger" /&gt;
@@ -141,7 +158,7 @@
The AdminService class in the example demonstrates this functionality and
is listed below.</para>
<programlisting> public class AdminService
<programlisting language="csharp"> public class AdminService
{
private string userName;
@@ -157,12 +174,12 @@
}</programlisting>
<para>Note that it does not inherit from any base class. To instruct
Spring to create a <classname>JobDetail</classname> object for this method
Spring to create a <literal>JobDetail</literal> object for this method
we use Spring's factory object class
<classname>MethodInvokingJobDetailFactoryObject</classname> as shown
<literal>MethodInvokingJobDetailFactoryObject</literal> as shown
below</para>
<programlisting> &lt;object id="adminService" type="Spring.Scheduling.Quartz.Example.AdminService, Spring.Scheduling.Quartz.Example"&gt;
<programlisting language="myxml"> &lt;object id="adminService" type="Spring.Scheduling.Quartz.Example.AdminService, Spring.Scheduling.Quartz.Example"&gt;
&lt;!-- we inject straight to target object --&gt;
&lt;property name="UserName" value="admin-service" /&gt;
&lt;/object&gt;
@@ -174,14 +191,14 @@
&lt;/object&gt;
</programlisting>
<para>Note that <classname>AdminService</classname> object is configured
<para>Note that <literal>AdminService</literal> object is configured
using Spring as you would do normally, without consideration for Quartz.
The trigger associated with the jobDetail object is listed below. Also
note that when using MethodInvokingJobDetailFactoryObject you can't use
database persistence for Jobs. See the class documentation for additional
details.</para>
<programlisting> &lt;object id="simpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz"&gt;
<programlisting language="myxml"> &lt;object id="simpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz"&gt;
&lt;!-- see the example of method invoking job above --&gt;
&lt;property name="jobDetail" ref="jobDetail" /&gt;
&lt;!-- 5 seconds --&gt;
@@ -200,7 +217,7 @@
<para>This trigger can then be added to the scheduler's list of registered
triggers as shown below.</para>
<programlisting> &lt;object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz"&gt;
<programlisting language="myxml"> &lt;object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="triggers"&gt;
&lt;list&gt;
&lt;ref object="cronTrigger" /&gt;

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
* Copyright 2002-2005 the original author or authors.
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-->
<chapter id="quickstarts">
<chapter xml:id="quickstarts" xmlns="http://docbook.org/ns/docbook" version="5">
<title>IoC Quickstarts</title>
<sect1>
@@ -26,7 +26,7 @@
the Spring.NET framework.</para>
</sect1>
<sect1 id="qs-moviefinder">
<sect1 xml:id="qs-moviefinder">
<title>Movie Finder</title>
<para>The source material for this simple demonstration of Spring.NET's
@@ -65,12 +65,12 @@
</imageobject>
</mediaobject></para>
<sect2 id="qs-mf-gettingstarted">
<sect2 xml:id="qs-mf-gettingstarted">
<title>Getting Started - Movie Finder</title>
<para>The startup class for the MovieFinder example is the
<literal>MovieApp</literal> class, which is an ordinary .NET class with
a single application entry point... <programlisting>using System;
a single application entry point... <programlisting language="csharp">using System;
namespace Spring.Examples.MovieFinder
{
public class MovieApp
@@ -91,7 +91,7 @@ namespace Spring.Examples.MovieFinder
custom configuration section in a standard .NET application config
file...</para>
<programlisting>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
<programlisting language="myxml">&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
@@ -115,7 +115,7 @@ namespace Spring.Examples.MovieFinder
<para>The body of the <literal>Main</literal> method in the
<literal>MovieApp</literal> class can now be fleshed out a little
further... <programlisting>
further... <programlisting language="csharp">
using System;
using Spring.Context;
...
@@ -129,14 +129,14 @@ using Spring.Context;
<literal>Spring.Context</literal> namespace gives the application access
to the <literal>IApplicationContext</literal> class that will serve as
the primary means for the application to access the IoC container. The
line of code... <programlisting>IApplicationContext ctx = ContextRegistry.GetContext();</programlisting>
line of code... <programlisting language="csharp">IApplicationContext ctx = ContextRegistry.GetContext();</programlisting>
... retrieves a fully configured <literal>IApplicationContext</literal>
implementation that has been configured using the named
<literal>&lt;objects/&gt;</literal> section from the application config
file.</para>
</sect2>
<sect2 id="qs-mf-firstobject">
<sect2 xml:id="qs-mf-firstobject">
<title>First Object Definition</title>
<para>As yet, no objects have been defined in the application config
@@ -144,7 +144,7 @@ using Spring.Context;
<literal>MovieLister</literal> instance that we are going to use in the
application can be seen in the following XML snippet...</para>
<programlisting>&lt;objects xmlns="http://www.springframework.net"&gt;
<programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"&gt;
&lt;object name="MyMovieLister"
type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder"&gt;
&lt;/object&gt;
@@ -158,7 +158,7 @@ using Spring.Context;
object so defined can be retrieved from the
<literal>IApplicationContext</literal> reference like so...</para>
<programlisting>...
<programlisting language="csharp">...
public static void Main ()
{
IApplicationContext ctx = ContextRegistry.GetContext();
@@ -177,21 +177,21 @@ using Spring.Context;
injected into the <literal>lister</literal> instance looks like
this...</para>
<programlisting>&lt;objects xmlns="http://www.springframework.net"&gt;
<programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"&gt;
&lt;object name="MyMovieFinder"
type="Spring.Examples.MovieFinder.SimpleMovieFinder, Spring.Examples.MovieFinder"/&gt;
&lt;/object&gt;
&lt;/objects&gt;</programlisting>
</sect2>
<sect2 id="qs-mf-setterinjection">
<sect2 xml:id="qs-mf-setterinjection">
<title>Setter Injection</title>
<para>What we want to do is inject the <literal>IMovieFinder</literal>
instance identified by the <literal>MyMovieFinder</literal> id into the
<literal>MovieLister</literal> instance identified by the
<literal>MyMovieLister</literal> id, which can be accomplished using
Setter Injection and the following XML... <programlisting>&lt;objects xmlns="http://www.springframework.net"&gt;
Setter Injection and the following XML... <programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"&gt;
&lt;object name="MyMovieLister"
type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder"&gt;
&lt;!-- using setter injection... --&gt;
@@ -210,7 +210,7 @@ using Spring.Context;
<literal>MovieLister</literal> object that is referenced in the
application is then fully configured and ready to be used in the
application to do what is does best... list movies by director.
<programlisting>...
<programlisting language="csharp">...
public static void Main ()
{
IApplicationContext ctx = ContextRegistry.GetContext();
@@ -235,12 +235,12 @@ using Spring.Context;
the reference documentation.</para>
</sect2>
<sect2 id="qs-mf-constructorinjection">
<sect2 xml:id="qs-mf-constructorinjection">
<title>Constructor Injection</title>
<para>Let's define another implementation of the
<literal>IMovieFinder</literal> interface in the application config
file...<programlisting>...
file...<programlisting language="myxml">...
&lt;object name="AnotherMovieFinder"
type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder, Spring.Examples.MovieFinder"&gt;
&lt;/object&gt;
@@ -248,18 +248,18 @@ using Spring.Context;
<literal>IMovieFinder</literal> implementation that uses a colon
delimited text file as it's movie source. The C# source code for this
class defines a single constructor that takes a
<classname>System.IO.FileInfo</classname> as it's single constructor
<literal>System.IO.FileInfo</literal> as it's single constructor
argument. As this object definition currently stands, attempting to get
this object out of the <literal>IApplicationContext</literal> in the
application with a line of code like so... <programlisting>IMovieFinder finder = (IMovieFinder) ctx.GetObject ("AnotherMovieFinder");</programlisting>
application with a line of code like so... <programlisting language="csharp">IMovieFinder finder = (IMovieFinder) ctx.GetObject ("AnotherMovieFinder");</programlisting>
will result in a fatal
<classname>Spring.Objects.Factory.ObjectCreationException</classname>,
<literal>Spring.Objects.Factory.ObjectCreationException</literal>,
because the
<classname>Spring.Examples.MovieFinder.ColonDelimitedMovieFinder</classname>
<literal>Spring.Examples.MovieFinder.ColonDelimitedMovieFinder</literal>
class does not have a default constructor that takes no arguments. If we
want to use this implementation of the <literal>IMovieFinder</literal>
interface, we will have to supply an appropriate constructor
argument...<programlisting>...
argument...<programlisting language="myxml">...
&lt;object name="AnotherMovieFinder"
type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder, Spring.Examples.MovieFinder"&gt;
&lt;constructor-arg index="0" value="movies.txt"/&gt;
@@ -269,11 +269,11 @@ using Spring.Context;
<para>Unsurprisingly, the &lt;constructor-arg/&gt; element is used to
supply constructor arguments to the constructors of managed objects. The
Spring.NET IoC container uses the functionality offered by
<classname>System.ComponentModel.TypeConverter</classname>
<literal>System.ComponentModel.TypeConverter</literal>
specializations to convert the <literal>movies.txt</literal> string into
an instance of the <classname>System.IO.FileInfo</classname> that is
an instance of the <literal>System.IO.FileInfo</literal> that is
required by the single constructor of the
<classname>Spring.Examples.MovieFinder.ColonDelimitedMovieFinder</classname>
<literal>Spring.Examples.MovieFinder.ColonDelimitedMovieFinder</literal>
(see <xref linkend="objects-objects-conversion" /> for a more in depth
treatment concerning the automatic type conversion functionality offered
by Spring.NET).</para>
@@ -283,7 +283,7 @@ using Spring.Context;
distinct object definitions in the config file of the example
application; if we wanted to, we could switch the implementation that
the <literal>MyMovieLister</literal> object uses like
so...<programlisting>...
so...<programlisting language="myxml">...
&lt;object name="MyMovieLister"
type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder"&gt;
&lt;!-- lets use the colon delimited implementation instead --&gt;
@@ -306,7 +306,7 @@ using Spring.Context;
<literal>MyMovieLister</literal> object.</para>
</sect2>
<sect2 id="qs-mf-summary">
<sect2 xml:id="qs-mf-summary">
<title>Summary</title>
<para>This example application is quite simple, and admittedly it
@@ -345,8 +345,8 @@ using Spring.Context;
log4net in your main application, declare some loggers in code, and then
log log log. (Sing along...) We are using App.config to configure the
loggers. As such, we declare the log4net configuration section handler
as shown below <programlisting>&lt;section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /&gt;</programlisting>
The corresponding configuration section looks like this <programlisting>
as shown below <programlisting language="myxml">&lt;section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /&gt;</programlisting>
The corresponding configuration section looks like this <programlisting language="myxml">
&lt;log4net&gt;
&lt;appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"&gt;
&lt;layout type="log4net.Layout.PatternLayout"&gt;
@@ -379,7 +379,7 @@ using Spring.Context;
<para>The logging name is up to you to decide when you declare the
logger in code. In the case of this example we used the convention of
giving the logging name the name of the fully qualified class name.
<programlisting>private static readonly ILog LOG = LogManager.GetLogger(typeof (MovieApp));</programlisting>
<programlisting language="csharp">private static readonly ILog LOG = LogManager.GetLogger(typeof (MovieApp));</programlisting>
Other conventions are to give the same logger name across multiple
classes that constitute a logical component or subsystem within the
application, for example a data access layer. One tip in selecting the
@@ -390,7 +390,7 @@ using Spring.Context;
format %logger{2}.</para>
<para>To initialize the logging system add the following to the start of
your application <programlisting>XmlConfigurator.Configure();</programlisting>
your application <programlisting language="csharp">XmlConfigurator.Configure();</programlisting>
Note that if you are using or reading information on version 1.2.0 this
used to be called DOMConfigurator.Configure();</para>
@@ -406,9 +406,9 @@ using Spring.Context;
objects. Coincidentally, the example code itself uses Spring in the
logger name, so this logger also controls the output level you see from
running MainApp. Finally, you are ready to use the simple logger api to
log, i.e. <programlisting>LOG.Info("Searching for movie...");</programlisting>
log, i.e. <programlisting language="csharp">LOG.Info("Searching for movie...");</programlisting>
Logging exceptions is another common task, which can be done using the
error level <programlisting>try {
error level <programlisting language="csharp">try {
//do work
{
catch (Exception e)
@@ -418,7 +418,7 @@ catch (Exception e)
</sect2>
</sect1>
<sect1 id="qs-appcontext-messagesource">
<sect1 xml:id="qs-appcontext-messagesource">
<title>ApplicationContext and IMessageSource</title>
<sect2>
@@ -453,7 +453,7 @@ catch (Exception e)
to the ResourceManager in other parts of your application. In the
example program an embedded resource file, MyResource.resx and a Spanish
specific resource file, MyResources.es.resx are declared in this manner.
The corresponding XML fragment is shown below <programlisting>...
The corresponding XML fragment is shown below <programlisting language="myxml">...
&lt;object name="messageSource" type="Spring.Context.Support.ResourceSetMessageSource, Spring.Core"&gt;
&lt;property name="resourceManagers"&gt;
&lt;list&gt;
@@ -484,7 +484,7 @@ catch (Exception e)
contains a text resource, <literal>Hello {0} {1}</literal> under the key
name <literal>HelloMessage</literal> (aka Keys.HELLO_MESSAGE) that can
be used for string text formatting purposes. The example code
<programlisting>
<programlisting language="csharp">
string msg = ctx.GetMessage(Keys.HELLO_MESSAGE,
CultureInfo.CurrentCulture,
"Mr.", "Anderson");
@@ -492,7 +492,7 @@ string msg = ctx.GetMessage(Keys.HELLO_MESSAGE,
the string with the passed argument values resulting in the text, "Hello
Mr. Anderson". The current culture is used to select the resource file
MyResource.resx. If instead the Spanish culture is specified
<programlisting>
<programlisting language="csharp">
CultureInfo spanishCultureInfo = new CultureInfo("es");
string esMsg = ctx.GetMessage(Keys.HELLO_MESSAGE,
spanishCultureInfo,
@@ -510,7 +510,7 @@ string esMsg = ctx.GetMessage(Keys.HELLO_MESSAGE,
into a key of its own, called <literal>FemaleGreeting</literal> (aka
Keys.FEMALE_GREETING). The replacement value for the message argument
{0} can then be made localization aware by wrapping the key in a
convenience class DefaultMessageResolvable. The code <programlisting>
convenience class DefaultMessageResolvable. The code <programlisting language="csharp">
string[] codes = {Keys.FEMALE_GREETING};
DefaultMessageResolvable dmr = new DefaultMessageResolvable(codes, null);
@@ -519,7 +519,7 @@ msg = ctx.GetMessage(Keys.HELLO_MESSAGE,
dmr, "Anderson");
</programlisting> will assign msg the value, Hello Mrs. Anderson, since the
value for the key <literal>FemaleGreeting</literal> in MyResource.resx
is 'Mrs.' Similarly, the code <programlisting>
is 'Mrs.' Similarly, the code <programlisting language="csharp">
esMsg = ctx.GetMessage(Keys.HELLO_MESSAGE,
spanishCultureInfo,
dmr, "Anderson");
@@ -536,7 +536,7 @@ esMsg = ctx.GetMessage(Keys.HELLO_MESSAGE,
property Name. The resource file, Person.resx contains key names that
follow the pattern, person.&lt;PropertyName&gt;. In this case it
contains person.Name and person.Age. The code to assign these resource
values to an object is shown below <programlisting>
values to an object is shown below <programlisting language="csharp">
Person p = new Person();
ctx.ApplyResources(p, "person", CultureInfo.CurrentUICulture);
</programlisting> While you could also use the Spring itself to set the

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="remoting-quickstart">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="remoting-quickstart" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Portable Service Abstraction Quick Start</title>
<sect1 id="qs-remoting-introduction">
<sect1 xml:id="qs-remoting-introduction">
<title>Introduction</title>
<para>This quickstart demonstrates the basic usage of Spring.NET's
@@ -12,17 +29,17 @@
shows the use of the WebServiceExporter.</para>
</sect1>
<sect1 id="qs-remoting-projectstructure">
<sect1 xml:id="qs-remoting-projectstructure">
<title>.NET Remoting Example</title>
<para>The infrastructure classes are located in the
<literal>Spring.Services</literal> assembly under the
<literal>Spring.Services.Remoting</literal> namespace. The overall
strategy is to export .NET objects on the server side as either CAO or SAO
objects using <classname>CaoExporter</classname> or
<classname>SaoExporter</classname> and obtain references to these objects
on the client side using <classname>CaoFactoryObject</classname> and
<classname>SaoFactoryObject</classname>. This quickstart does assume
objects using <literal>CaoExporter</literal> or
<literal>SaoExporter</literal> and obtain references to these objects
on the client side using <literal>CaoFactoryObject</literal> and
<literal>SaoFactoryObject</literal>. This quickstart does assume
familiarity with .NET Remoting on the part of the reader. If you are new
to .NET remoting you may find the links to introductory remoting material
presented at the conclusion of this quickstart of some help.</para>
@@ -46,23 +63,23 @@
</mediaobject></para>
<para>The <literal>Spring.Calculator.Contract</literal> project contains
the interface <classname>ICalculator</classname> that defines the basic
the interface <literal>ICalculator</literal> that defines the basic
operations of a calculator and another interface
<classname>IAdvancedCalculator</classname> that adds support for memory
<literal>IAdvancedCalculator</literal> that adds support for memory
storage for results. (woo hoo - big feature - HP-12C beware!) These
interfaces are shown below. The
<literal>Spring.Calculator.Services</literal> project contains an
implementation of the these interfaces, namely the classes
<classname>Calculator</classname> and
<classname>AdvancedCalculator</classname>. The purpose of the
<classname>AdvancedCalculator</classname> implementation is to demonstrate
<literal>Calculator</literal> and
<literal>AdvancedCalculator</literal>. The purpose of the
<literal>AdvancedCalculator</literal> implementation is to demonstrate
the configuration of object state for SAO-singleton objects. Note that the
calculator implementations <emphasis>do not</emphasis> inherit from the
<classname>MarshalByRefObject</classname> class. The
<literal>MarshalByRefObject</literal> class. The
<literal>Spring.Calculator.ClientApp</literal> project contains the client
application and the <literal>Spring.Calculator.RemoteApp</literal> project
contains a console application that will host a Remoted instance of the
<classname>AdvancedCalculator</classname> class. The
<literal>AdvancedCalculator</literal> class. The
<literal>Spring.Aspects</literal> project contains some logging advice
that will be used to demonstrate the application of aspects to remoted
objects. <literal>Spring.Calculator.RegisterComponentServices</literal> is
@@ -70,7 +87,7 @@
quickstart. <literal>Spring.Calculator.Web</literal> is related to web
services exporters and is not relevant for this quickstart.</para>
<programlisting>public interface ICalculator
<programlisting language="csharp">public interface ICalculator
{
int Add(int n1, int n2);
@@ -103,7 +120,7 @@ public class DivisionResult
<para>An extension of this interface that supports having a slot for
calculator memory is shown below</para>
<programlisting>public interface IAdvancedCalculator : ICalculator
<programlisting language="csharp">public interface IAdvancedCalculator : ICalculator
{
int GetMemory();
@@ -137,7 +154,7 @@ public class DivisionResult
barrage of OO design ranting finished, on to the implementation!</para>
</sect1>
<sect1 id="qs-remoting-implementation">
<sect1 xml:id="qs-remoting-implementation">
<title>Implementation</title>
<para>The implementation of the calculators contained in the
@@ -147,7 +164,7 @@ public class DivisionResult
using constructor injection. A subset of the implementation is shown
below.</para>
<programlisting>public class Calculator : ICalculator
<programlisting language="csharp">public class Calculator : ICalculator
{
public int Add(int n1, int n2)
@@ -197,11 +214,11 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
}</programlisting>
<para>The <classname>Spring.Calculator.RemotedApp</classname> project
<para>The <literal>Spring.Calculator.RemotedApp</literal> project
hosts remoted objects inside a console application. The code is also quite
simple and shown below</para>
<programlisting>public static void Main(string[] args)
<programlisting language="csharp">public static void Main(string[] args)
{
try
{
@@ -227,7 +244,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
(<literal>App.config</literal>). In this case we are using the
<literal>tcp</literal> channel on port <literal>8005</literal>.</para>
<programlisting>&lt;system.runtime.remoting&gt;
<programlisting language="myxml">&lt;system.runtime.remoting&gt;
&lt;application&gt;
&lt;channels&gt;
&lt;channel ref="tcp" port="8005" /&gt;
@@ -240,7 +257,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
remoting configurations. The AOP advice used in this example is a simple
Log4Net based around advice.</para>
<programlisting> &lt;configSections&gt;
<programlisting language="myxml"> &lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" /&gt;
&lt;section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" /&gt;
@@ -310,8 +327,8 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
property values and / or object references is done as you would normally
do for any object declared in the Spring.NET configuration file. To expose
the calculator objects as .NET remoted objects the exporter
<classname>Spring.Remoting.CaoExporter</classname> is used for CAO objects
and <classname>Spring.Remoting.SaoExporter</classname> is used for SAO
<literal>Spring.Remoting.CaoExporter</literal> is used for CAO objects
and <literal>Spring.Remoting.SaoExporter</literal> is used for SAO
objects. Both exporters require the setting of a
<literal>TargetName</literal> property that refers to the name of the
object in Spring's IoC container that will be remoted. The semantics of
@@ -323,7 +340,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
property <literal>Infinite</literal> is set to true.</para>
<para>The configuration for the exporting a SAO-Singleton is shown
below.<programlisting>&lt;objects
below.<programlisting language="myxml">&lt;objects
xmlns="http://www.springframework.net"
xmlns:r="http://www.springframework.net/remoting"&gt;
@@ -334,16 +351,16 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
serviceName="RemotedSaoSingletonCalculator" /&gt;
&lt;/objects&gt;</programlisting>The configuration shown above uses the Spring
Remoting schema but you can also choose to use the standard 'generic' XML
configuration shown below.<programlisting>&lt;object name="saoSingletonCalculator" type="Spring.Remoting.SaoExporter, Spring.Services"&gt;
configuration shown below.<programlisting language="myxml">&lt;object name="saoSingletonCalculator" type="Spring.Remoting.SaoExporter, Spring.Services"&gt;
&lt;property name="TargetName" value="singletonCalculator" /&gt;
&lt;property name="ServiceName" value="RemotedSaoSingletonCalculator" /&gt;
&lt;/object&gt;</programlisting> This will result in the remote object being
identified by the URL
<literal>tcp://localhost:8005/RemotedSaoSingletonCalculator</literal>. The
use of <classname>SaoExporter</classname> and
<classname>CaoExporter</classname> for other configuration are similar,
use of <literal>SaoExporter</literal> and
<literal>CaoExporter</literal> for other configuration are similar,
look at the configuration files in the
<classname>Spring.Calculator.RemotedApp</classname> project files for more
<literal>Spring.Calculator.RemotedApp</literal> project files for more
information.</para>
<para>On the client side, the client application will connect a specific
@@ -354,7 +371,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
application configuration file (<literal>App.config</literal>), as can
been seen below.</para>
<programlisting>&lt;system.runtime.remoting&gt;
<programlisting language="myxml">&lt;system.runtime.remoting&gt;
&lt;application&gt;
&lt;channels&gt;
&lt;channel ref="tcp"/&gt;
@@ -364,7 +381,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
<para>The client implementation code is shown below.</para>
<programlisting>public static void Main(string[] args)
<programlisting language="csharp">public static void Main(string[] args)
{
try
{
@@ -410,7 +427,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
Components (Enterprise Services) of the calculator object but are not
discussed in this QuickStart.</para>
<programlisting>
<programlisting language="myxml">
&lt;spring&gt;
&lt;context&gt;
&lt;resource uri="config://spring/objects" /&gt;
@@ -450,7 +467,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
</programlisting>
<para>The inProcess.xml configuration file creates an instance of
AdvancedCalculator directly <programlisting>
AdvancedCalculator directly <programlisting language="myxml">
&lt;objects xmlns="http://www.springframework.net"&gt;
&lt;description&gt;inProcess&lt;/description&gt;
@@ -462,10 +479,10 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
<para>Factory classes are used to create a client side reference to the
.NET remoting implementations. For SAO objects use the
<classname>SaoFactoryObject</classname> class and for CAO objects use the
<classname>CaoFactoryObject</classname> class. The configuration for
<literal>SaoFactoryObject</literal> class and for CAO objects use the
<literal>CaoFactoryObject</literal> class. The configuration for
obtaining a reference to the previously exported SAO singleton
implementation is shown below <programlisting>&lt;objects xmlns="http://www.springframework.net"&gt;
implementation is shown below <programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"&gt;
&lt;description&gt;saoSingleton&lt;/description&gt;
@@ -486,7 +503,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
to easily switch between test, QA, and production (yea baby!)
environments. An example of how this would be expressed is...</para>
<programlisting>&lt;property name="ServiceUrl" value="${protocol}://${host}:${port}/RemotedSaoSingletonCalculator" /&gt;</programlisting>
<programlisting language="myxml">&lt;property name="ServiceUrl" value="${protocol}://${host}:${port}/RemotedSaoSingletonCalculator" /&gt;</programlisting>
<para>The property values in this example are defined elsewhere; refer to
<xref linkend="objects-factory-placeholderconfigurer" /> for additional
@@ -496,7 +513,7 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
making a simple change to the configuration file.</para>
<para>The configuration for obtaining a reference to the previously
exported CAO implementation is shown below <programlisting>&lt;objects xmlns="http://www.springframework.net"&gt;
exported CAO implementation is shown below <programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"&gt;
&lt;description&gt;cao&lt;/description&gt;
@@ -558,7 +575,7 @@ Memory = 2
definitions which should give you a good feel for how to use the
schema.</para>
<programlisting>&lt;!-- Calculator definitions --&gt;
<programlisting language="myxml">&lt;!-- Calculator definitions --&gt;
&lt;object id="singletonCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"&gt;
&lt;constructor-arg type="int" value="217" /&gt;
&lt;/object&gt;
@@ -588,8 +605,8 @@ Memory = 2
method on the remoted object is invoked for the SAO case.</para>
</sect1>
<sect1>
<title id="entsvc-example">.NET Enterprise Services Example</title>
<sect1 xml:id="entsvc-example">
<title>.NET Enterprise Services Example</title>
<para>The .NET Enterprise Services example is located in the project
Spring.Calculator.RegisterComponentServices.2005.csproj or
@@ -600,7 +617,7 @@ Memory = 2
Spring.Calculator.RegisterComponentServices.Config. The top level
configuration is shown below</para>
<programlisting> &lt;spring&gt;
<programlisting language="myxml"> &lt;spring&gt;
&lt;context&gt;
&lt;resource uri="config://spring/objects" /&gt;
@@ -625,7 +642,7 @@ Memory = 2
AccessControl and Roles properties. The configuration file for
enterpriseServices.xml is shown below</para>
<para><programlisting>&lt;objects xmlns="http://www.springframework.net"&gt;
<para><programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"&gt;
&lt;description&gt;enterpriseService&lt;/description&gt;
@@ -681,7 +698,7 @@ Memory = 2
&lt;/objects&gt;</programlisting></para>
</sect1>
<sect1 id="websvc-example">
<sect1 xml:id="websvc-example">
<title>Web Services Example</title>
<para>The WebServices example shows how to export the AdvancedCalculator
@@ -689,7 +706,7 @@ Memory = 2
logging advice applied to it. The main configuration file, Web.config,
includes information from three locations as shown below</para>
<programlisting> &lt;context&gt;
<programlisting language="myxml"> &lt;context&gt;
&lt;resource uri="config://spring/objects"/&gt;
&lt;resource uri="~/Config/webServices.xml"/&gt;
&lt;resource uri="~/Config/webServices-aop.xml"/&gt;
@@ -698,7 +715,7 @@ Memory = 2
<para>The config section 'spring/objects' in Web.config contains the
definition for the 'plain' Advanced calculator, as well as the definitions
to create an AOP proxy of an AdvancedCalculator that adds logging advice.
These definitions are shown below<programlisting> &lt;objects xmlns="http://www.springframework.net"&gt;
These definitions are shown below<programlisting language="myxml"> &lt;objects xmlns="http://www.springframework.net"&gt;
&lt;!-- Aspect --&gt;
@@ -724,7 +741,7 @@ Memory = 2
&lt;/objects&gt;</programlisting>The configuration file webService.xml
simply exports the named calculator object</para>
<programlisting> &lt;object id="calculatorService" type="Spring.Web.Services.WebServiceExporter, Spring.Web"&gt;
<programlisting language="myxml"> &lt;object id="calculatorService" type="Spring.Web.Services.WebServiceExporter, Spring.Web"&gt;
&lt;property name="TargetName" value="calculator" /&gt;
&lt;property name="Namespace" value="http://SpringCalculator/WebServices" /&gt;
&lt;property name="Description" value="Spring Calculator Web Services" /&gt;
@@ -733,7 +750,7 @@ Memory = 2
<para>Whereas the webService-aop.xml exports the calculator instance that
has AOP advice applied to it.</para>
<programlisting> &lt;object id="calculatorServiceWeaved" type="Spring.Web.Services.WebServiceExporter, Spring.Web"&gt;
<programlisting language="myxml"> &lt;object id="calculatorServiceWeaved" type="Spring.Web.Services.WebServiceExporter, Spring.Web"&gt;
&lt;property name="TargetName" value="calculatorWeaved" /&gt;
&lt;property name="Namespace" value="http://SpringCalculator/WebServices" /&gt;
&lt;property name="Description" value="Spring Calculator Web Services" /&gt;
@@ -780,7 +797,7 @@ Memory = 2
2007-10-15 17:59:47,421 [DEBUG] Spring.Aspects.Logging.CommonLoggingAroundAdvice - Intercepted call : returned '4'</programlisting>
</sect1>
<sect1 id="qs-remoting-additional">
<sect1 xml:id="qs-remoting-additional">
<title>Additional Resources</title>
<para>Some introductory articles on .NET remoting can be found online at

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="remoting">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="remoting" xmlns="http://docbook.org/ns/docbook" version="5">
<title>.NET Remoting</title>
<section id="remoting-introduction">
<section xml:id="remoting-introduction">
<title>Introduction</title>
<para>Spring's .NET Remoting support allows you to export a 'plain .NET
@@ -32,7 +49,7 @@
item.</para>
</section>
<section id="remoting-publishsao">
<section xml:id="remoting-publishsao">
<title>Publishing SAOs on the Server</title>
<para>Exposing a Singleton SAO service can be done in two ways. The first
@@ -45,7 +62,7 @@
<literal>RemotingServices.Marshal</literal>. This method overcomes the
limitations of the first method. Example server side code for publishing
an SAO singleton object with a predefined state is shown below
<programlisting>AdvancedMBRCalculator calc = new AdvancedMBRCalculator(217);
<programlisting language="csharp">AdvancedMBRCalculator calc = new AdvancedMBRCalculator(217);
RemotingServices.Marshal(calc, "MyRemotedCalculator");</programlisting></para>
<para>The class AdvancedMBRCalculator used above inherits from
@@ -54,18 +71,18 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");</programlisting></para>
<para>If your design calls for configuring a singleton SAO, or using a
non-default constructor, you can use the Spring IoC container to create
the SAO instance, configure it, and register it with the .NET remoting
infrastructure. The <classname>SaoExporter</classname> class performs this
infrastructure. The <literal>SaoExporter</literal> class performs this
task and most importantly, will automatically create a proxy class that
inherits from MarshalbyRefObject if your business object does not already
do so. The following XML taken from the <link
linkend="remoting-quickstart">Remoting QuickStart</link> demonstrates its
usage to an SAO Singleton object</para>
<section id="sao-singleton">
<section xml:id="sao-singleton">
<title>SAO Singleton</title>
</section>
<programlisting>&lt;object id="singletonCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"&gt;
<programlisting language="myxml">&lt;object id="singletonCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"&gt;
&lt;constructor-arg type="int" value="217"/&gt;
&lt;/object&gt;
@@ -80,14 +97,14 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");</programlisting></para>
"RemotedSaoSingletonCalculator". (The fully qualified url is
tcp://localhost:8005/RemotedSaoSingleCallCalculator using the standard
.NET channel configuration shown further below.)
<classname>AdvancedCalculator</classname> class implements the business
interface <classname>IAdvancedCalculator</classname>. The current proxy
<literal>AdvancedCalculator</literal> class implements the business
interface <literal>IAdvancedCalculator</literal>. The current proxy
implementation requires that your business objects implement an interface.
The interfaces' methods will be the ones exposed in the generated .NET
remoting proxy. The initial memory of the calculator is set to 217 via the
constructor. The class <classname>AdvancedCalculator</classname>
constructor. The class <literal>AdvancedCalculator</literal>
<emphasis>does not</emphasis> inherit from
<classname>MarshalByRefObject</classname>. Also note that the exporter
<literal>MarshalByRefObject</literal>. Also note that the exporter
sets the lifetime of the SAO Singleton to infinite so that the singleton
will not be garbage collected after 5 minutes (the .NET default lease
time). If you would like to vary the lifetime properties, they are
@@ -95,7 +112,7 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");</programlisting></para>
<para>A custom schema is provided to make the object declaration even
easier and with intellisense support for the attributes. This is shown
below<programlisting>&lt;objects xmlns="http://www.springframework.net"
below<programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"
xmlns:r="http://www.springframework.net/remoting"&gt;
&lt;r:saoExporter targetName="singletonCalculator"
@@ -106,12 +123,12 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");</programlisting></para>
&lt;/objects&gt;</programlisting>Refer to the end of this chapter for more
information on Spring's .NET custom schema.</para>
<section id="sao-singlecall">
<section xml:id="sao-singlecall">
<title>SAO SingleCall</title>
</section>
<para>The following XML fragment shows how to expose the calculator
service in SAO 'SingleCall' mode. <programlisting>&lt;object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
service in SAO 'SingleCall' mode. <programlisting language="myxml">&lt;object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
singleton="false"&gt;
&lt;constructor-arg type="int" value="217"/&gt;
&lt;/object&gt;
@@ -129,7 +146,7 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");</programlisting></para>
singleton calculator, the following standard AOP configuration is used to
create the target for the SaoExporter</para>
<programlisting>&lt;object id="singletonCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop"&gt;
<programlisting language="myxml">&lt;object id="singletonCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop"&gt;
&lt;property name="target" ref="singletonCalculator"/&gt;
&lt;property name="interceptorNames"&gt;
&lt;list&gt;
@@ -146,15 +163,15 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");</programlisting></para>
<note>As generally required with a .NET Remoting application, the
arguments to your service methods should be Serializable.</note>
<sect2 id="remoting-configuration">
<sect2 xml:id="remoting-configuration">
<title>Console Application Configuration</title>
<para>When using <classname>SaoExporter</classname> you can still use
<para>When using <literal>SaoExporter</literal> you can still use
the standard remoting administration section in the application
configuration file to register the channel.
<classname>ChannelServices</classname> as shown below</para>
<literal>ChannelServices</literal> as shown below</para>
<programlisting>&lt;system.runtime.remoting&gt;
<programlisting language="myxml">&lt;system.runtime.remoting&gt;
&lt;application&gt;
&lt;channels&gt;
&lt;channel ref="tcp" port="8005" /&gt;
@@ -166,7 +183,7 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");</programlisting></para>
initialize the .NET Remoting infrastructure with a call to
RemotingConfiguration (since we are using the .config file for channel
registration) and then start the Spring application context. This is
shown below <programlisting>RemotingConfiguration.Configure("RemoteApp.exe.config");
shown below <programlisting language="csharp">RemotingConfiguration.Configure("RemoteApp.exe.config");
IApplicationContext ctx = ContextRegistry.GetContext();
@@ -176,23 +193,23 @@ Console.ReadLine();
</programlisting></para>
<para>You can also put in the configuration file an instance of the
object <classname>Spring.Remoting.RemotingConfigurer</classname> to make
object <literal>Spring.Remoting.RemotingConfigurer</literal> to make
the RemotingConfiguration call show above on your behalf during
initialization of the IoC container. The
<classname>RemotingConfigurer</classname> implements the
<interfacename>IObjectFactoryPostProcessor</interfacename> interface,
<literal>RemotingConfigurer</literal> implements the
<literal>IObjectFactoryPostProcessor</literal> interface,
which gets called after all object definitions have been loaded but
before they have been instantiated, (See<xref
linkend="objects-factory-customizing-factory-postprocessors" /> for more
information). The RemotingConfigurer has two properties you can
configure. <classname>Filename</classname>, that specifies the filename
configure. <literal>Filename</literal>, that specifies the filename
to load the .NET remoting configuration from (if null the default file
name is used) and <classname>EnsureSecurity</classname> which makes sure
name is used) and <literal>EnsureSecurity</literal> which makes sure
the channel in encrypted (available only on .NET 2.0). As a convenience,
the custom Spring remoting schema can be used to define an instance of
this class as shown below, taken from the <link
linkend="remoting-quickstart">Remoting QuickStart</link>
<programlisting>&lt;objects xmlns="http://www.springframework.net"
<programlisting language="myxml">&lt;objects xmlns="http://www.springframework.net"
xmlns:r="http://www.springframework.net/remoting"&gt;
&lt;r:configurer filename="Spring.Calculator.RemoteApp.exe.config" /&gt;
@@ -205,7 +222,7 @@ Console.ReadLine();
code in action.</para>
</sect2>
<section id="iis-application">
<section xml:id="iis-application">
<title>IIS Application Configuration</title>
<para>If you are deploying a .NET remoting application inside IIS there
@@ -219,7 +236,7 @@ Console.ReadLine();
Spring IoC container inside the application start method defined in
Global.asax, as shown below</para>
<programlisting> void Application_Start(object sender, EventArgs e)
<programlisting language="csharp"> void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
@@ -241,7 +258,7 @@ Console.ReadLine();
</section>
</section>
<section id="remoting-clientsao">
<section xml:id="remoting-clientsao">
<title>Accessing a SAO on the Client</title>
<para>Administrative type registration on the client side lets you easily
@@ -267,17 +284,17 @@ Console.ReadLine();
object is a SAO object. A call to <literal>Activator.GetObject</literal>
will instantiate a SAO proxy on the client. For CAO objects another
mechanism is used and is discussed later. The code to obtain the SAO proxy
is shown below <programlisting>ICalculator calc = (ICalculator)Activator.GetObject (
is shown below <programlisting language="csharp">ICalculator calc = (ICalculator)Activator.GetObject (
typeof (ICalculator),
"tcp://localhost:8005/MyRemotedCalculator");</programlisting></para>
<para>To obtain a reference to a SAO proxy within the IoC container, you
can use the object factory <classname>SaoFactoryObject</classname> in the
can use the object factory <literal>SaoFactoryObject</literal> in the
Spring configuration file. The following XML taken from the <link
linkend="remoting-quickstart"> Remoting QuickStart</link> demonstrates its
usage.</para>
<programlisting>&lt;object id="calculatorService" type="Spring.Remoting.SaoFactoryObject, Spring.Services"&gt;
<programlisting language="myxml">&lt;object id="calculatorService" type="Spring.Remoting.SaoFactoryObject, Spring.Services"&gt;
&lt;property name="ServiceInterface" value="Spring.Calculator.Interfaces.IAdvancedCalculator, Spring.Calculator.Contract" /&gt;
&lt;property name="ServiceUrl" value="tcp://localhost:8005/RemotedSaoSingletonCalculator" /&gt;
&lt;/object&gt;</programlisting>
@@ -287,11 +304,11 @@ Console.ReadLine();
server and published object name.</para>
<para>Other objects in the IoC container that depend on an implementation
of the interface <classname>ICalculator</classname> can now refer to the
of the interface <literal>ICalculator</literal> can now refer to the
object "calculatorService", thereby using a remote implementation of this
interface. The exposure of dependencies among objects within the IoC
container lets you easily switch the implementation of
<classname>ICalculator</classname>. By using the IoC container changing
<literal>ICalculator</literal>. By using the IoC container changing
the application to use a local instead of remote implementation is a
configuration file change, not a code change. By promoting interface based
programing, the ability to switch implementation makes it easier to unit
@@ -304,7 +321,7 @@ Console.ReadLine();
integrate with the server implementation when it is ready.</para>
</section>
<section id="remoting-cao-introduction">
<section xml:id="remoting-cao-introduction">
<title>CAO best practices</title>
<para>Creating a client activated object (CAO) is typically done by
@@ -320,7 +337,7 @@ Console.ReadLine();
factory per class, we can create a generic SAO object factory to return
CAO references to objects defined in Spring's application context. This
functionality is encapsulated in Spring's
<classname>CaoExporter</classname> class. On the client side a reference
<literal>CaoExporter</literal> class. On the client side a reference
is obtained using <literal>CaoFactoryObject</literal>. The client side
factory object supports creation of the CAO object using constructor
arguments. In addition to reducing the clutter and tedium around creating
@@ -334,14 +351,14 @@ Console.ReadLine();
resources.</para>
</section>
<section id="remoting-publishcao">
<section xml:id="remoting-publishcao">
<title>Registering a CAO object on the Server</title>
<para>To expose an object as a CAO on the server you should declare an
object in the standard Spring configuration that is a 'prototype', that is
the singleton property is set to false. This results in a new object being
created each time it is retrieved from Spring's IoC container. An
implementation of <interfacename>ICaoRemoteFactory</interfacename> is what
implementation of <literal>ICaoRemoteFactory</literal> is what
is exported via a call to RemotingServices.Marshal. This implementation
uses Spring's IoC container to create objects and then dynamically create
a .NET remoting proxy for the retrieved object. Note that the default
@@ -351,14 +368,14 @@ Console.ReadLine();
<para>This is best shown using an example from the Remoting Quickstart
application. Here is the definition of a simple calculator object,</para>
<para><programlisting>&lt;object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
<para><programlisting language="myxml">&lt;object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
singleton="false"&gt;
&lt;constructor-arg type="int" value="217" /&gt;
&lt;/object&gt;</programlisting>To export this as a CAO object we can declare
the <classname>CaoExporter</classname> object directly in the server's XML
the <literal>CaoExporter</literal> object directly in the server's XML
configuration file, as shown below</para>
<programlisting>&lt;object id="caoCalculator" type="Spring.Remoting.CaoExporter, Spring.Services"&gt;
<programlisting language="myxml">&lt;object id="caoCalculator" type="Spring.Remoting.CaoExporter, Spring.Services"&gt;
&lt;property name="TargetName" value="prototypeCalculator" /&gt;
&lt;property name="Infinite" value="false" /&gt;
&lt;property name="InitialLeaseTime" value="2m" /&gt;
@@ -372,7 +389,7 @@ Console.ReadLine();
<para>Alternatively, you can use the remoting schema and declare the CAO
object as shown below</para>
<programlisting>&lt;r:caoExporter targetName="prototypeCalculator" infinite="false"&gt;
<programlisting language="myxml">&lt;r:caoExporter targetName="prototypeCalculator" infinite="false"&gt;
&lt;r:lifeTime initialLeaseTime="2m" renewOnCallTime="1m" /&gt;
&lt;/r:caoExporter&gt;</programlisting>
@@ -386,7 +403,7 @@ Console.ReadLine();
from the Remoting QuickStart, a calculator with logging around advice is
defined as shown below.</para>
<programlisting>&lt;object id="prototypeCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop"&gt;
<programlisting language="myxml">&lt;object id="prototypeCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop"&gt;
&lt;property name="targetSource"&gt;
&lt;object type="Spring.Aop.Target.PrototypeTargetSource, Spring.Aop"&gt;
&lt;property name="TargetObjectName" value="prototypeCalculator" /&gt;
@@ -403,19 +420,19 @@ Console.ReadLine();
linkend="aop" /> for more information. The CAO exporter then references
with the name 'prototypeCalculatorWeaved' as shown below.</para>
<programlisting>&lt;r:caoExporter targetName="prototypeCalculatorWeaved" infinite="false"&gt;
<programlisting language="myxml">&lt;r:caoExporter targetName="prototypeCalculatorWeaved" infinite="false"&gt;
&lt;r:lifeTime initialLeaseTime="2m" renewOnCallTime="1m" /&gt;
&lt;/r:caoExporter&gt;</programlisting>
</section>
</section>
<section id="remoting-clientcao">
<section xml:id="remoting-clientcao">
<title>Accessing a CAO on the Client</title>
<para>On the client side a CAO reference is obtained by using the
<classname>CaoFactoryObject</classname> as shown below</para>
<literal>CaoFactoryObject</literal> as shown below</para>
<programlisting>&lt;object id="calculatorService" type="Spring.Remoting.CaoFactoryObject, Spring.Services"&gt;
<programlisting language="myxml">&lt;object id="calculatorService" type="Spring.Remoting.CaoFactoryObject, Spring.Services"&gt;
&lt;property name="RemoteTargetName" value="prototypeCalculator" /&gt;
&lt;property name="ServiceUrl" value="tcp://localhost:8005" /&gt;
&lt;/object&gt;</programlisting>
@@ -424,14 +441,14 @@ Console.ReadLine();
previous section. The property 'RemoteTargetName' identifies the object on
the server side. Using this approach the client can obtain an reference
though standard DI techniques to a remote object that implements the
<interfacename>IAdvancedCalculator</interfacename> interface. (As always,
<literal>IAdvancedCalculator</literal> interface. (As always,
that doesn't mean the client should treat the object as if it was an
in-process object).</para>
<para>Alternatively, you can use the Remoting schema to shorten this
definition and provide intellisense code completion</para>
<programlisting>&lt;r:caoFactory id="calculatorService"
<programlisting language="myxml">&lt;r:caoFactory id="calculatorService"
remoteTargetName="prototypeCalculator"
serviceUrl="tcp://localhost:8005" /&gt;</programlisting>
@@ -440,12 +457,12 @@ Console.ReadLine();
<para>Applying AOP advice to a client side CAO object is done just like
any other object. Simply use the id of the object created by the
<classname>CaoFactoryObject</classname> as the AOP target, i.e.
<literal>CaoFactoryObject</literal> as the AOP target, i.e.
'calculatorService' in the previous example.</para>
</section>
</section>
<section id="remoting-schema">
<section xml:id="remoting-schema">
<title>XML Schema for configuration</title>
<para>Please install the XSD schemas into VS.NET as described in <xref
@@ -455,7 +472,7 @@ Console.ReadLine();
objects.</para>
</section>
<section id="remoting-additional">
<section xml:id="remoting-additional">
<title>Additional Resources</title>
<para>Two articles that describe the process of creating a standard SAO

View File

@@ -1,14 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="resources">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="resources" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Resources</title>
<section id="objects-iresource">
<section xml:id="objects-iresource">
<title>Introduction</title>
<para>The <literal>IResource</literal> interface contained in the
<literal>Spring.Core.IO</literal> namespace provides a common interface to
describe and access data from diverse resource locations. This abstraction
lets you treat the <classname>InputStream</classname> from a file and from
lets you treat the <literal>InputStream</literal> from a file and from
a URL in a polymorphic and protocol-independent manner... the .NET BCL
does not provide such an abstraction. The <literal>IResource</literal>
interface inherits from <literal>IInputStream</literal> that provides a
@@ -21,11 +38,11 @@
</section>
<section>
<title>The <interfacename>IResource</interfacename> interface</title>
<title>The <literal>IResource</literal> interface</title>
<para>The IResource interface is shown below</para>
<programlisting>public interface IResource : IInputStreamSource
<programlisting language="csharp">public interface IResource : IInputStreamSource
{
bool IsOpen { get; }
@@ -61,7 +78,7 @@
<entry><literal>InputStream</literal></entry>
<entry>Inherited from IInputStream. Opens and returns a
<classname>System.IO.Stream</classname>. It is expected that each
<literal>System.IO.Stream</literal>. It is expected that each
invocation returns a fresh Stream. It is the responsibility of the
caller to close the stream.</entry>
</row>
@@ -81,7 +98,7 @@
cannot be read multiple times, and must be read once only and then
closed to avoid resource leaks. Will be false for all usual
resource implementations, with the exception of
<interfacename>InputStreamResource</interfacename>.</entry>
<literal>InputStreamResource</literal>.</entry>
</row>
<row>
@@ -100,7 +117,7 @@
<row>
<entry><literal>File</literal></entry>
<entry>Returns a <classname>System.IO.FileInfo</classname> for
<entry>Returns a <literal>System.IO.FileInfo</literal> for
this resource if it can be resolved to an absolute file
path.</entry>
</row>
@@ -145,7 +162,7 @@
<para>The Resource 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>IApplicationContext</interfacename> implementations), take
<literal>IApplicationContext</literal> implementations), take
a String which is used to create a Resource appropriate to that context
implementation</para>
@@ -206,7 +223,7 @@
a wrapper around a raw
<classname>System.IO.Stream</classname>
<literal>System.IO.Stream</literal>
. Uri syntax is not supported.
</listitem>
@@ -227,37 +244,37 @@
<title>Registering custom IResource implementations</title>
<para>The configuration section handler,
<classname>ResourceHandlersSectionHandler</classname>, is used to
register any custom <interfacename>IResource</interfacename>
<literal>ResourceHandlersSectionHandler</literal>, is used to
register any custom <literal>IResource</literal>
implementations you have created. In the configuration section you list
the type of <interfacename>IResource</interfacename> implementation and
the type of <literal>IResource</literal> implementation and
the protocol prefix. Your custom
<interfacename>IResource</interfacename> implementation must provide a
<literal>IResource</literal> implementation must provide a
constructor that takes a string as it's sole argument that represents
the URI string. Refer to the SDK documentation for
<classname>ResourceHandlersSectionHandler</classname> for more
<literal>ResourceHandlersSectionHandler</literal> for more
information. An example of the
<classname>ResourceHandlersSectionHandler</classname> is shown below for
a fictional <interfacename>IResource</interfacename> implementation that
<literal>ResourceHandlersSectionHandler</literal> is shown below for
a fictional <literal>IResource</literal> implementation that
interfaces with a database.</para>
<programlisting>&lt;configuration&gt;
<programlisting language="myxml">&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;section name='context' type='Spring.Context.Support.ContextHandler, Spring.Core'/&gt;
<emphasis role="bold"> &lt;section name="resourceHandlers"
type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/&gt;</emphasis>
&lt;section name="resourceHandlers"
type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
<emphasis role="bold"> &lt;resourceHandlers&gt;
&lt;resourceHandlers&gt;
&lt;handler protocol="db" type="MyCompany.MyApp.Resources.MyDbResource, MyAssembly"/&gt;
&lt;/resourceHandlers&gt;</emphasis>
&lt;/resourceHandlers&gt;
&lt;context&gt;
&lt;resource uri="db://user:pass@dbName/MyDefinitionsTable"/&gt;
@@ -269,21 +286,21 @@
</section>
<section>
<title>The <interfacename>IResourceLoader</interfacename></title>
<title>The <literal>IResourceLoader</literal></title>
<para>To load resources given their Uri syntax, an implementation of the
<classname>IResourceLoader</classname> is used. The default implementation
is <classname>ConfigurableResourceLoader</classname>. Typically you will
<literal>IResourceLoader</literal> is used. The default implementation
is <literal>ConfigurableResourceLoader</literal>. Typically you will
not need to access this class directly since the
<classname>IApplicationContext</classname> implements the
<classname>IResourceLoader</classname> interface that contains the single
<literal>IApplicationContext</literal> implements the
<literal>IResourceLoader</literal> interface that contains the single
method <literal>IResource GetResource(string location)</literal>. The
provided implementations of <literal>IApplicationContext</literal>
delegate this method to an instance of
<classname>ConfigurableResourceLoader</classname> which supports the Uri
<literal>ConfigurableResourceLoader</literal> which supports the Uri
protocols/schemes listed previously. If you do not specify a protocol then
the file protocol is used. The following shows some sample
usage.<programlisting>IResource resource = appContext.GetResource("http://www.springframework.net/license.html");
usage.<programlisting language="csharp">IResource resource = appContext.GetResource("http://www.springframework.net/license.html");
resource = appContext.GetResource("assembly://Spring.Core.Tests/Spring/TestResource.txt");
resource = appContext.GetResource("https://sourceforge.net/");
resource = appContext.GetResource("file:///C:/WINDOWS/ODBC.INI");
@@ -299,7 +316,7 @@ Console.WriteLine(reader.ReadToEnd());</programlisting> Other protocols can be
<para>The <literal>CreateRelative</literal> method allows you to easily
load resources based on a relative path name. In the case of relative
assembly resources, the relative path navigates the namespace within an
assembly. For example: <programlisting>IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt");
assembly. For example: <programlisting language="csharp">IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt");
IResource res2 = res.CreateRelative("./IO/TestIOResource.txt");</programlisting>
This loads the resource <literal>TestResource.txt</literal> and then
navigates to the <literal>Spring.Core.IO</literal> namespace and loads the
@@ -307,14 +324,14 @@ IResource res2 = res.CreateRelative("./IO/TestIOResource.txt");</programlisting>
</section>
<section>
<title>The <interfacename>IResourceLoaderAware</interfacename>
<title>The <literal>IResourceLoaderAware</literal>
interface</title>
<para>The <interfacename>IResourceLoaderAware</interfacename> interface is
<para>The <literal>IResourceLoaderAware</literal> interface is
a special marker interface, identifying objects that expect to be provided
with a <interfacename>IResourceLoader</interfacename> reference.</para>
with a <literal>IResourceLoader</literal> reference.</para>
<programlisting>public interface IResourceLoaderAware
<programlisting language="csharp">public interface IResourceLoaderAware
{
IResourceLoader ResourceLoader
{
@@ -324,29 +341,29 @@ IResource res2 = res.CreateRelative("./IO/TestIOResource.txt");</programlisting>
}</programlisting>
<para>When a class implements
<interfacename>IResourceLoaderAware</interfacename> and is deployed into
<literal>IResourceLoaderAware</literal> and is deployed into
an application context (as a Spring-managed object), it is recognized as
<interfacename>IResourceLoaderAware</interfacename> by the application
<literal>IResourceLoaderAware</literal> by the application
context. The application context will then invoke the ResourceLoader
property, supplying itself as the argument (remember, all application
contexts in Spring implement the
<interfacename>IResourceLoader</interfacename> interface).</para>
<literal>IResourceLoader</literal> interface).</para>
<para>Of course, since an
<interfacename>IApplicationContext</interfacename> is a
<interfacename>IResourceLoader</interfacename>, the object could also
implement the <interfacename>IApplicationContextAware</interfacename>
<literal>IApplicationContext</literal> is a
<literal>IResourceLoader</literal>, the object could also
implement the <literal>IApplicationContextAware</literal>
interface and use the supplied application context directly to load
resources, but in general, it's better to use the specialized
<interfacename>IResourceLoader</interfacename> interface if that's all
<literal>IResourceLoader</literal> 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>IApplicationContext</interfacename>
Spring <literal>IApplicationContext</literal>
interface.</para>
</section>
<section>
<title>Application contexts and <interfacename>IResource</interfacename>
<title>Application contexts and <literal>IResource</literal>
paths</title>
<para>An application context constructor (for a specific application
@@ -355,7 +372,7 @@ IResource res2 = res.CreateRelative("./IO/TestIOResource.txt");</programlisting>
of the context. For example, you can create an XmlApplicationContext from
two resources as follows:</para>
<programlisting>IApplicationContext context = new XmlApplicationContext(
<programlisting language="csharp">IApplicationContext context = new XmlApplicationContext(
"file://objects.xml", "assembly://MyAssembly/MyProject/objects-dal-layer.xml");
</programlisting>
</section>

View File

@@ -1,41 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="scheduling">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="scheduling" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Scheduling and Thread Pooling</title>
<section id="scheduling-introduction">
<section xml:id="scheduling-introduction">
<title>Introduction</title>
<para>The Spring Framework features integration classes for scheduling
support. Currently, Spring supports the Quartz Scheduler (<ulink
url="http://quartznet.sourceforge.net/"></ulink>). The scheduler is set up
using a <interfacename>IFactoryObject</interfacename> with optional
references to <classname>Trigger</classname> instances, respectively.
using a <literal>IFactoryObject</literal> with optional
references to <literal>Trigger</literal> instances, respectively.
Furthermore, a convenience class for both the Quartz Scheduler is
available that allows you to invoke a method of an existing target
object.</para>
</section>
<section id="scheduling-quartz">
<section xml:id="scheduling-quartz">
<title>Using the Quartz.NET Scheduler</title>
<para>Quartz uses <classname>Trigger</classname>,
<classname>Job</classname> and <classname>JobDetail</classname> objects to
<para>Quartz uses <literal>Trigger</literal>,
<literal>Job</literal> and <literal>JobDetail</literal> objects to
realize scheduling of all kinds of jobs. For the basic concepts behind
Quartz, have a look at <ulink
url="http://quartznet.sourceforge.net/"></ulink>. 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">
<section xml:id="scheduling-quartz-jobdetail">
<title>Using the JobDetailObject</title>
<para><classname>JobDetail</classname> objects contain all information
<para><literal>JobDetail</literal> objects contain all information
needed to run a job. The Spring Framework provides a
<classname>JobDetailObject</classname> that makes the
<classname>JobDetail</classname> easier to configure and with sensible
<literal>JobDetailObject</literal> that makes the
<literal>JobDetail</literal> easier to configure and with sensible
defaults. Let's have a look at an example:</para>
<programlisting>
<programlisting language="myxml">
&lt;object name="ExampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="JobType" value="Example.Quartz.ExampleJob, Example.Quartz" /&gt;
&lt;property name="JobDataAsMap"&gt;
@@ -46,17 +63,17 @@
&lt;/object&gt;</programlisting>
<para>The job detail object has all information it needs to run the job
(<classname>ExampleJob</classname>). The timeout is specified in the job
(<literal>ExampleJob</literal>). The timeout is specified in the job
data dictionary. The job data dictonary is available through the
<classname>JobExecutionContext</classname> (passed to you at execution
time), but the <classname>JobDetailObject</classname> also maps the
<literal>JobExecutionContext</literal> (passed to you at execution
time), but the <literal>JobDetailObject</literal> 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
this case, if the <literal>ExampleJob</literal> contains a property
named <literal>Timeout</literal>, the
<classname>JobDetailObject</classname> will automatically apply
<literal>JobDetailObject</literal> will automatically apply
it:</para>
<programlisting>namespace Example.Quartz;
<programlisting language="csharp">namespace Example.Quartz;
public class ExampleJob extends QuartzJobObject {
@@ -85,15 +102,15 @@ public class ExampleJob extends QuartzJobObject {
<literal>ExampleJob</literal>).</emphasis></para>
</section>
<section id="scheduling-quartz-method-invoking-job">
<section xml:id="scheduling-quartz-method-invoking-job">
<title>Using the
<classname>MethodInvokingJobDetailFactoryObject</classname></title>
<literal>MethodInvokingJobDetailFactoryObject</literal></title>
<para>Often you just need to invoke a method on a specific object. Using
the <classname>MethodInvokingJobDetailFactoryObject</classname> you can
the <literal>MethodInvokingJobDetailFactoryObject</literal> you can
do exactly this:</para>
<programlisting>&lt;object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz"&gt;
<programlisting language="myxml">&lt;object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="TargetObject" ref="ExampleBusinessObject" /&gt;
&lt;property name="TargetMethod" value="DoIt" /&gt;
&lt;/object&gt;</programlisting>
@@ -102,7 +119,7 @@ public class ExampleJob extends QuartzJobObject {
method being called on the <literal>exampleBusinessObject</literal>
method (see below):</para>
<programlisting>public class ExampleBusinessObject {
<programlisting language="csharp">public class ExampleBusinessObject {
<lineannotation>// properties and collaborators</lineannotation>
@@ -111,28 +128,28 @@ public class ExampleJob extends QuartzJobObject {
}
}</programlisting>
<programlisting>
<programlisting language="myxml">
&lt;object id="ExampleBusinessObject" type="Examples.BusinessObjects.ExampleBusinessObject, Examples.BusinessObjects"/&gt;</programlisting>
<para>Using the
<classname>MethodInvokingJobDetailFactoryObject</classname>, you don't
<literal>MethodInvokingJobDetailFactoryObject</literal>, 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
triggers for the same <literal>JobDetail</literal>, 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.
start. If <literal>JobDetail</literal> classes implement the
<literal>Stateful</literal> interface, this won't happen.
The second job will not start before the first one has finished. To make
jobs resulting from the
<classname>MethodInvokingJobDetailFactoryObject</classname>
<literal>MethodInvokingJobDetailFactoryObject</literal>
non-concurrent, set the <literal>concurrent</literal> flag to
<literal>false</literal>.</para>
<programlisting>&lt;object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz"&gt;
<programlisting language="myxml">&lt;object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="TargetObject" ref="ExampleBusinessObject" /&gt;
&lt;property name="TargetMethod" value="DoIt" /&gt;
&lt;property name="Concurrent" value="false" /&gt;
@@ -148,27 +165,27 @@ public class ExampleJob extends QuartzJobObject {
</note>
</section>
<section id="scheduling-quartz-cron">
<section xml:id="scheduling-quartz-cron">
<title>Wiring up jobs using triggers and the
<classname>SchedulerFactoryObject</classname></title>
<literal>SchedulerFactoryObject</literal></title>
<para>We've created job details and jobs. We've also reviewed the
convenience class 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>SchedulerFactoryObject</classname>. Several triggers are
<literal>SchedulerFactoryObject</literal>. Several triggers are
available within Quartz. Spring offers two subclassed triggers with
convenient defaults: <classname>CronTriggerObject</classname> and
<classname>SimpleTriggerObject</classname></para>
convenient defaults: <literal>CronTriggerObject</literal> and
<literal>SimpleTriggerObject</literal></para>
<para>Triggers need to be scheduled. Spring offers a
<classname>SchedulerFactoryObject</classname> that exposes triggers to
be set as properties. <classname>SchedulerFactoryObject</classname>
<literal>SchedulerFactoryObject</literal> that exposes triggers to
be set as properties. <literal>SchedulerFactoryObject</literal>
schedules the actual jobs with those triggers.</para>
<para>Find below a couple of examples:</para>
<programlisting>&lt;object id="SimpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz"&gt;
<programlisting language="myxml">&lt;object id="SimpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz"&gt;
&lt;!-- see the example of method invoking job above --&gt;
&lt;property name="JobDetail" ref="ExampleJob" /&gt;
@@ -190,9 +207,9 @@ public class ExampleJob extends QuartzJobObject {
<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>SchedulerFactoryObject</classname>:</para>
<literal>SchedulerFactoryObject</literal>:</para>
<programlisting>&lt;object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz"&gt;
<programlisting language="myxml">&lt;object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="triggers"&gt;
&lt;list&gt;
&lt;ref object="CronTrigger" /&gt;
@@ -203,7 +220,7 @@ public class ExampleJob extends QuartzJobObject {
</programlisting>
<para>More properties are available for the
<classname>SchedulerFactoryObjecct</classname> for you to set, such as
<literal>SchedulerFactoryObjecct</literal> 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">SchedulerFactoryObject

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="services">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="services" xmlns="http://docbook.org/ns/docbook" version="5">
<title>.NET Enterprise Services</title>
<sect1 id="services-introduction">
<sect1 xml:id="services-introduction">
<title>Introduction</title>
<para>Spring's .NET Enterprise Services support allows you to export a
@@ -16,14 +33,14 @@
Programatically, as you would with any third party library.</para>
</sect1>
<sect1 id="services-servicedcomponents">
<sect1 xml:id="services-servicedcomponents">
<title>Serviced Components</title>
<para>Services components in .NET are able to use COM+ services such as
declarative and distributed transactions, role based security, object
pooling messaging. To access these services your class needs to derive
from the class
<classname>System.EnterpriseServices.ServicedComponent</classname>, adorn
<literal>System.EnterpriseServices.ServicedComponent</literal>, adorn
your class and assemblies with relevant attributes, and configure your
application by registering your serviced components with the COM+ catalog.
The overall landscape of accessing and using COM+ services within .NET
@@ -50,7 +67,7 @@
linkend="entsvc-example">NET Enterprise Services example.</link></para>
</sect1>
<sect1 id="services-serverside">
<sect1 xml:id="services-serverside">
<title>Server Side</title>
<para>One of the main challenges for the exporting of a serviced component
@@ -64,7 +81,7 @@
<listitem>
<classname>Spring.Enterprise.ServicedComponentExporter</classname>
<literal>Spring.Enterprise.ServicedComponentExporter</literal>
is responsible for exporting a single component and making sure that it derives from ServicedComponent class. It also allows you to specify class-level and method-level attributes for the component in order to define things such as transactional behavior, queuing, etc.
</listitem>
@@ -72,7 +89,7 @@
<listitem>
<classname>Spring.Enterprise.EnterpriseServicesExporter</classname>
<literal>Spring.Enterprise.EnterpriseServicesExporter</literal>
corresponds to a COM+ application, and it allows you to specify list of components that should be included in the application, as well as the application name and other assembly-level attributes
</listitem>
@@ -81,7 +98,7 @@
<para>Let's say that we have a simple service interface and implementation
class, such as these:</para>
<programlisting>namespace MyApp.Services
<programlisting language="csharp">namespace MyApp.Services
{
public interface IUserManager
{
@@ -116,7 +133,7 @@
<para>And the corresponding object definition for it in the application
context config file:</para>
<programlisting>&lt;object id="userManager" type="MyApp.Services.SimpleUserManager"&gt;
<programlisting language="myxml">&lt;object id="userManager" type="MyApp.Services.SimpleUserManager"&gt;
&lt;property name="UserDao" ref="userDao"/&gt;
&lt;/object&gt;</programlisting>
@@ -125,7 +142,7 @@
to export our service using the exporter
<literal>ServicedComponentExporter</literal> as shown below</para>
<programlisting>&lt;object id="MyApp.EnterpriseServices.UserManager" type="Spring.Enterprise.ServicedComponentExporter, Spring.Services"&gt;
<programlisting language="myxml">&lt;object id="MyApp.EnterpriseServices.UserManager" type="Spring.Enterprise.ServicedComponentExporter, Spring.Services"&gt;
&lt;property name="TargetName" value="userManager"/&gt;
&lt;property name="TypeAttributes"&gt;
&lt;list&gt;
@@ -152,7 +169,7 @@
<para>The next thing we need to do is configure an exporter for the COM+
application that will host our new component:</para>
<programlisting>&lt;object id="MyComponentExporter" type="Spring.Enterprise.EnterpriseServicesExporter, Spring.Services"&gt;
<programlisting language="myxml">&lt;object id="MyComponentExporter" type="Spring.Enterprise.EnterpriseServicesExporter, Spring.Services"&gt;
&lt;property name="ApplicationName" value="My COM+ Application"/&gt;
&lt;property name="Description" value="My enterprise services application."/&gt;
&lt;property name="AccessControl"&gt;
@@ -182,18 +199,18 @@
AccessControl and Roles properties.</para>
</sect1>
<sect1 id="services-clientside">
<sect1 xml:id="services-clientside">
<title>Client Side</title>
<para>Because serviced component classes are dynamically generated and
registered, you cannot instantiate them in your code using the new
operator. Instead, you need to use
<classname>Spring.Enterprise.ServicedComponentFactory</classname>
<literal>Spring.Enterprise.ServicedComponentFactory</literal>
definition, which also allows you to specify the configuration template
for the component as well as the name of the remote server the component
is running on, if necessary. An example is shown below</para>
<programlisting>&lt;object id="enterpriseUserManager" type="Spring.Enterprise.ServicedComponentFactory, Spring.Services"&gt;
<programlisting language="myxml">&lt;object id="enterpriseUserManager" type="Spring.Enterprise.ServicedComponentFactory, Spring.Services"&gt;
&lt;property name="Name" value="MyApp.EnterpriseServices.UserManager"/&gt;
&lt;property name="Template" value="userManager"/&gt;
&lt;/object&gt;</programlisting>

View File

@@ -1,5 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="springair">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="springair" xmlns="http://docbook.org/ns/docbook" version="5">
<title>SpringAir - Reference Application</title>
<sect1>
@@ -87,7 +104,7 @@
instantiate the IoC container. The important parts of that configuration
are shown below</para>
<programlisting>&lt;spring&gt;
<programlisting language="myxml">&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" /&gt;
&lt;/parsers&gt;
@@ -142,7 +159,7 @@
<para>The XML configuration to configure the TripForm form is shown
below</para>
<programlisting> &lt;object type="TripForm.aspx" parent="standardPage"&gt;
<programlisting language="myxml"> &lt;object type="TripForm.aspx" parent="standardPage"&gt;
&lt;property name="BookingAgent" ref="bookingAgent" /&gt;
&lt;property name="AirportDao" ref="airportDao" /&gt;
&lt;property name="TripValidator" ref="tripValidator" /&gt;
@@ -172,7 +189,7 @@
family of methods that are overridden to support the bi-directional data
binding are listed below.</para>
<programlisting> protected override void InitializeModel()
<programlisting language="csharp"> protected override void InitializeModel()
{
trip = new Trip();
trip.Mode = TripMode.RoundTrip;
@@ -215,7 +232,7 @@
below. Notice how much cleaner and more business focused the code reads
than if you were using standard ASP.NET APIs.</para>
<programlisting> protected void SearchForFlights(object sender, EventArgs e)
<programlisting language="csharp"> protected void SearchForFlights(object sender, EventArgs e)
{
if (Validate(trip, tripValidator))
{
@@ -234,7 +251,7 @@
defined declaratively in the XML configuration file and is shown
below.</para>
<programlisting> &lt;v:group id="tripValidator"&gt;
<programlisting language="myxml"> &lt;v:group id="tripValidator"&gt;
&lt;v:required id="departureAirportValidator" test="StartingFrom.AirportCode"&gt;
&lt;v:message id="error.departureAirport.required" providers="departureAirportErrors, validationSummary"/&gt;
@@ -290,7 +307,7 @@
methods. Spring can expose this object as a web service by declaring the
following XML defined in the top level Config/Services.xml file</para>
<programlisting> &lt;object id="bookingAgentWebService" type="Spring.Web.Services.WebServiceExporter, Spring.Web"&gt;
<programlisting language="myxml"> &lt;object id="bookingAgentWebService" type="Spring.Web.Services.WebServiceExporter, Spring.Web"&gt;
&lt;property name="TargetName" value="bookingAgent"/&gt;
&lt;property name="Name" value="BookingAgent"/&gt;
&lt;property name="Namespace" value="http://SpringAir/WebServices"/&gt;

View File

@@ -264,14 +264,3 @@ div.warning * td {
font-size: 100%;
}
.programlisting .interfacename,
.programlisting .literal,
.programlisting .classname {
font-size: 95%;
}
/* everything in a <lineannotation/> is displayed in a nice green, comment-like color */
.programlisting * .lineannotation,
.programlisting * .lineannotation * {
color: green;
}

View File

@@ -1,8 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter id="testing">
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="testing" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Testing</title>
<section id="testing-introduction">
<section xml:id="testing-introduction">
<title>Introduction</title>
<para>The Spring team considers developer testing to be an absolutely
@@ -14,7 +31,7 @@
linkend="integration-testing">integration testing</link>.</para>
</section>
<section id="unit-testing">
<section xml:id="unit-testing">
<title>Unit testing</title>
<para>One of the main benefits of Dependency Injection is that your code
@@ -39,7 +56,7 @@
<emphasis>unit</emphasis> tests for your IoC-based applications.</para>
</section>
<section id="integration-testing">
<section xml:id="integration-testing">
<title>Integration testing</title>
<para>However, it is also important to be able to perform some integration
@@ -72,7 +89,7 @@
with NUnit then you should add the following to your .config file, (in
the form of MyAssembly.dll.config)</para>
<programlisting>&lt;runtime&gt;
<programlisting language="myxml">&lt;runtime&gt;
&lt;assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"&gt;
@@ -91,7 +108,7 @@
</note>
<para>The <literal>Spring.Testing.NUnit</literal> namespace provides
valuable NUnit <classname>TestCase</classname> superclasses for
valuable NUnit <literal>TestCase</literal> superclasses for
integration testing using a Spring container. Note that as of NUnit 2.4
these can be rewritten in terms of custom attributes via NUnit's new
extensibility mechanism. This will be an additional option in an upcoming
@@ -124,7 +141,7 @@
</listitem>
</itemizedlist>
<section id="testing-ctx-management">
<section xml:id="testing-ctx-management">
<title>Context management and caching</title>
<para>The <literal><literal>Spring.Testing.NUnit</literal></literal>
@@ -140,11 +157,11 @@
could reduce productivity.</para>
<para>To address this issue, the
<classname>AbstractDependencyInjectionSpringContextTests</classname> has
<literal>AbstractDependencyInjectionSpringContextTests</literal> has
an <literal>protected</literal> property that subclasses must implement
to provide the location of context definition files:</para>
<programlisting>protected abstract string[] ConfigLocations { get; }</programlisting>
<programlisting language="csharp">protected abstract string[] ConfigLocations { get; }</programlisting>
<para>Implementations of this method must provide an array containing
the IResource locations of XML configuration metadata used to configure
@@ -160,34 +177,34 @@
reloading - for example, by changing an object definition or the state
of an application object - you can call the
<methodname>SetDirty()</methodname> method on
<classname>AbstractDependencyInjectionSpringContextTests</classname> to
<literal>AbstractDependencyInjectionSpringContextTests</literal> to
cause the test fixture to reload the configurations and rebuild the
application context before executing the next test case.</para>
</section>
<section id="testing-fixture-di">
<section xml:id="testing-fixture-di">
<title>Dependency Injection of test fixtures</title>
<para>When
<classname>AbstractDependencyInjectionSpringContextTests</classname>
<literal>AbstractDependencyInjectionSpringContextTests</literal>
(and subclasses) load your application context, they can optionally
configure instances of your test classes by Setter Injection. All you
need to do is to define instance variables and the corresponding
setters.
<classname>AbstractDependencyInjectionSpringContextTests</classname>
<literal>AbstractDependencyInjectionSpringContextTests</literal>
will automatically locate the corresponding object in the set of
configuration files specified in the
<methodname>ConfigLocations</methodname> property.</para>
<para>Consider the scenario where we have a class,
<classname>HibernateTitleDao</classname>, that performs data access
logic for say, the <classname>Title</classname> domain object. We want
<literal>HibernateTitleDao</literal>, that performs data access
logic for say, the <literal>Title</literal> domain object. We want
to write integration tests that test all of the following areas:</para>
<itemizedlist>
<listitem>
<para>The Spring configuration; basically, is everything related to
the configuration of the <classname>HibernateTitleDao</classname>
the configuration of the <literal>HibernateTitleDao</literal>
object correct and present?</para>
</listitem>
@@ -197,7 +214,7 @@
</listitem>
<listitem>
<para>The logic of the <classname>HibernateTitleDao</classname>;
<para>The logic of the <literal>HibernateTitleDao</literal>;
does the configured instance of this class perform as
anticipated?</para>
</listitem>
@@ -206,8 +223,8 @@
<para>Let's look at the test class itself (we will look at the
configuration immediately afterwards).</para>
<programlisting>[TestFixture]
public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyInjectionSpringContextTests</emphasis> {
<programlisting language="csharp">[TestFixture]
public class HibernateTitleDaoTests : AbstractDependencyInjectionSpringContextTests {
<lineannotation>// this instance will be (automatically) dependency injected</lineannotation>
private HibernateTitleDao titleDao;
@@ -234,10 +251,10 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
(<literal>'classpath:com/foo/daos.xml'</literal>) looks like
this:</para>
<programlisting>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
<programlisting language="myxml">&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;objects xmlns="http://www.springframework.net"&gt;
<lineannotation>&lt;!-- this object will be injected into the <classname>HibernateTitleDaoTests</classname> class --&gt;</lineannotation>
<lineannotation>&lt;!-- this object will be injected into the <literal>HibernateTitleDaoTests</literal> class --&gt;</lineannotation>
&lt;object id="titleDao" type="Spring.Samples.HibernateTitleDao, Spring.Samples"&gt;
&lt;property name="sessionFactory" ref="sessionFactory"/&gt;
&lt;/object&gt;
@@ -249,7 +266,7 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
&lt;/objects&gt;</programlisting>
<para>The
<classname>AbstractDependencyInjectionSpringContextTests</classname>
<literal>AbstractDependencyInjectionSpringContextTests</literal>
classes uses <link linkend="objects-factory-autowire"><emphasis>autowire
by type</emphasis></link>. Thus if you have multiple object definitions
of the same type, you cannot rely on this approach for those particular
@@ -260,13 +277,13 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
<para>If you don't want dependency injection applied to your test cases,
simply don't declare any set properties. Alternatively, you can extend
the <classname>AbstractSpringContextTests</classname> - the root of the
the <literal>AbstractSpringContextTests</literal> - the root of the
class hierarchy in the <literal>Spring.Testing.NUnit</literal>
namespace. It merely contains convenience methods to load Spring
contexts, and performs no Dependency Injection of the test
fixture.</para>
<section id="testing-fixture-di-field">
<section xml:id="testing-fixture-di-field">
<title>Field level injection</title>
<para>If, for whatever reason, you don't fancy having setter
@@ -276,8 +293,8 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
Spring XML configuration does not need to change, merely the test
fixture).</para>
<programlisting>[TestFixture]
public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyInjectionSpringContextTests</emphasis> {
<programlisting language="csharp">[TestFixture]
public class HibernateTitleDaoTests : AbstractDependencyInjectionSpringContextTests{
public HibernateTitleDaoTests() {
<lineannotation> // switch on field level injection</lineannotation>
@@ -307,7 +324,7 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
</section>
</section>
<section id="testing-tx">
<section xml:id="testing-tx">
<title>Transaction management</title>
<para>One common issue in tests that access a real database is their
@@ -317,23 +334,23 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
data - cannot be done (or verified) outside a transaction.</para>
<para>The
<classname>AbstractTransactionalDbProviderSpringContextTests</classname>
<literal>AbstractTransactionalDbProviderSpringContextTests</literal>
superclass (and subclasses) exist to meet this need. By default, they
create and roll back a transaction for each test. You simply write code
that can assume the existence of a transaction. If you call
transactionally proxied objects in your tests, they will behave
correctly, according to their transactional semantics.</para>
<para><classname>AbstractTransactionalSpringContextTests</classname>
depends on a <classname>IPlatformTransactionManager</classname> object
<para><literal>AbstractTransactionalSpringContextTests</literal>
depends on a <literal>IPlatformTransactionManager</literal> object
being defined in the application context. The name doesn't matter, due
to the use of autowire by type.</para>
<para>Typically you will extend the subclass,
<classname>AbstractTransactionalDbProviderSpringContextTests</classname>.
This also requires that a <classname>DbProvider</classname> object
<literal>AbstractTransactionalDbProviderSpringContextTests</literal>.
This also requires that a <literal>DbProvider</literal> object
definition - again, with any name - be present in the configurations. It
creates an <classname>AdoTemplate</classname> instance variable that is
creates an <literal>AdoTemplate</literal> instance variable that is
useful for convenient querying, and provides handy methods to delete the
contents of selected tables (remember that the transaction will roll
back by default, so this is safe to do).</para>
@@ -341,7 +358,7 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
<para>If you want a transaction to commit - unusual, but occasionally
useful when you want a particular test to populate the database - you
can call the <methodname>SetComplete()</methodname> method inherited
from <classname>AbstractTransactionalSpringContextTests</classname>.
from <literal>AbstractTransactionalSpringContextTests</literal>.
This will cause the transaction to commit instead of roll back.</para>
<para>There is also convenient ability to end a transaction before the
@@ -357,27 +374,27 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
operation of the UI through your NUnit test suite.</para>
</section>
<section id="testing-superclasses">
<section xml:id="testing-superclasses">
<title>Convenience variables</title>
<para>When you extend the
<classname>AbstractTransactionalDbProviderSpringContextTests</classname>
<literal>AbstractTransactionalDbProviderSpringContextTests</literal>
class you will have access to the following <literal>protected</literal>
instance variables:</para>
<itemizedlist>
<listitem>
<para><literal>applicationContext</literal> (a
<interfacename>IConfigurableApplicationContext</interfacename>):
<literal>IConfigurableApplicationContext</literal>):
inherited from the
<classname>AbstractDependencyInjectionSpringContextTests</classname>
<literal>AbstractDependencyInjectionSpringContextTests</literal>
superclass. Use this to perform explicit object lookup, or test the
state of the context as a whole.</para>
</listitem>
<listitem>
<para><literal>adoTemplate</literal>: inherited from
<classname>AbstractTransactionalDbProviderSpringContextTests</classname>.
<literal>AbstractTransactionalDbProviderSpringContextTests</literal>.
Useful for querying to confirm state. For example, you might query
before and after testing application code that creates an object and
persists it using an ORM tool, to verify that the data appears in
@@ -385,7 +402,7 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
of the same transaction.) You will need to tell your ORM tool to
'flush' its changes for this to work correctly, for example using
the <methodname>Flush()</methodname> method on NHibernate's
<classname>ISession</classname> interface.</para>
<literal>ISession</literal> interface.</para>
</listitem>
</itemizedlist>
@@ -394,10 +411,10 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
in many tests</para>
</section>
<section id="testing-examples-petclinic"></section>
<section xml:id="testing-examples-petclinic"></section>
</section>
<section id="testing-resources">
<section xml:id="testing-resources">
<title>Further Resources</title>
<para>This section contains links to further resources about testing in

Some files were not shown because too many files have changed in this diff Show More