Update reference documentation generation tools to get source highlighting [SPRNET-1045]
88
doc/reference/docbook.build
Normal 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>
|
||||
|
Before Width: | Height: | Size: 374 B |
|
Before Width: | Height: | Size: 743 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 321 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1003 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 598 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 318 B |
|
Before Width: | Height: | Size: 259 B |
|
Before Width: | Height: | Size: 264 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 743 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 329 B |
|
Before Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 361 B |
|
Before Width: | Height: | Size: 244 B |
|
Before Width: | Height: | Size: 565 B |
|
Before Width: | Height: | Size: 244 B |
|
Before Width: | Height: | Size: 617 B |
|
Before Width: | Height: | Size: 244 B |
|
Before Width: | Height: | Size: 623 B |
|
Before Width: | Height: | Size: 244 B |
|
Before Width: | Height: | Size: 411 B |
|
Before Width: | Height: | Size: 244 B |
|
Before Width: | Height: | Size: 640 B |
|
Before Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 353 B |
|
Before Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 350 B |
|
Before Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 345 B |
|
Before Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 348 B |
|
Before Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 355 B |
|
Before Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 344 B |
|
Before Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 357 B |
|
Before Width: | Height: | Size: 968 B |
|
Before Width: | Height: | Size: 357 B |
@@ -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">
|
||||
<object id="ContactWebService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
|
||||
<property name="TargetName" value="ContactService"/>
|
||||
<property name="Namespace" value="http://Spring.Examples.Atlas/ContactService"/>
|
||||
@@ -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">
|
||||
<sectionGroup name="spring">
|
||||
<section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
|
||||
</sectionGroup>
|
||||
|
||||
</programlisting> <programlisting>
|
||||
</programlisting>
|
||||
<programlisting language="myxml">
|
||||
<spring>
|
||||
<context>
|
||||
<resource uri="~/Spring.config"/>
|
||||
@@ -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">
|
||||
<httpHandlers>
|
||||
<remove verb="*" path="*.asmx"/>
|
||||
<add verb="*" path="*.asmx" validate="false" type="Spring.Web.Script.Services.ScriptHandlerFactory, Spring.Web.Extensions"/>
|
||||
@@ -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">
|
||||
<modules>
|
||||
<add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||
<add name="SpringModule" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
|
||||
@@ -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)
|
||||
|
||||
@@ -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> <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>
|
||||
<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>
|
||||
|
||||
<!-- 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>
|
||||
<!-- 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><object name="exceptionHandlingAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
|
||||
<property name="exceptionHandlers">
|
||||
<list>
|
||||
<value><emphasis role="bold">on exception name ArithmeticException wrap System.InvalidOperationException</emphasis></value>
|
||||
</list>
|
||||
</property>
|
||||
</object></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
|
||||
<list> 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><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>
|
||||
<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><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"/>
|
||||
<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"/>
|
||||
|
||||
<property name="Separator" value=";"/>
|
||||
<property name="LogLevel" value="Info"/>
|
||||
<property name="Separator" value=";"/>
|
||||
<property name="LogLevel" value="Info"/>
|
||||
|
||||
|
||||
<property name="HideProxyTypeNames" value="true"/>
|
||||
<property name="UseDynamicLogger" value="true"/>
|
||||
</object></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><object name="exceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop">
|
||||
<property name="retryExpression" value="<emphasis role="bold">on exception name ArithmeticException retry 3x delay 1s</emphasis>"/>
|
||||
</object></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> <object id="<emphasis role="bold">validationAdvice</emphasis>" type="Spring.Aspects.Validation.ParameterValidationAdvice, Spring.Aop"/>
|
||||
<programlisting language="myxml"><![CDATA[<object id="validationAdvice" type="Spring.Aspects.Validation.ParameterValidationAdvice, Spring.Aop"/>
|
||||
|
||||
<object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
|
||||
<property name="ObjectNames">
|
||||
<list>
|
||||
<value>bookingAgent</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="InterceptorNames">
|
||||
<list>
|
||||
<value><emphasis role="bold">validationAdvice</emphasis></value>
|
||||
</list>
|
||||
</property>
|
||||
</object></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>
|
||||
|
||||
@@ -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> <object id="consoleLoggingAroundAdvice"
|
||||
<programlisting language="myxml"> <object id="consoleLoggingAroundAdvice"
|
||||
type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"/>
|
||||
<object id="myServiceObject" type="Spring.Aop.Framework.ProxyFactoryObject">
|
||||
<property name="target">
|
||||
@@ -222,50 +239,50 @@
|
||||
</property>
|
||||
</object></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> <object id="consoleLoggingAroundAdvice"
|
||||
<programlisting language="myxml"> <object id="consoleLoggingAroundAdvice"
|
||||
type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor">
|
||||
<property name="pattern" value="Do"/>
|
||||
<property name="advice">
|
||||
@@ -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> <object id="beforeAdvice"
|
||||
<programlisting language="myxml"> <object id="beforeAdvice"
|
||||
type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/>
|
||||
|
||||
<object id="myServiceObject"
|
||||
@@ -558,7 +575,7 @@
|
||||
</object></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> <object id="afterAdvice"
|
||||
<programlisting language="myxml"> <object id="afterAdvice"
|
||||
type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"/>
|
||||
|
||||
<object id="myServiceObject"
|
||||
@@ -669,7 +686,7 @@
|
||||
</object></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> <object id="throwsAdvice"
|
||||
<programlisting language="myxml"> <object id="throwsAdvice"
|
||||
type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"/>
|
||||
|
||||
<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> <object id="throwsAdvice"
|
||||
<programlisting language="myxml"> <object id="throwsAdvice"
|
||||
type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"/>
|
||||
<object id="afterAdvice"
|
||||
type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"/>
|
||||
@@ -950,7 +967,7 @@
|
||||
</object></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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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><objects xmlns='http://www.springframework.net'>
|
||||
<para><programlisting language="myxml"><objects xmlns='http://www.springframework.net'>
|
||||
|
||||
<alias name='SqlServer-2.0' alias='SqlServer2005'/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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><objects xmlns="http://www.springframework.net"
|
||||
<programlisting language="myxml"><objects xmlns="http://www.springframework.net"
|
||||
xmlns:db="http://www.springframework.net/database">
|
||||
|
||||
<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> <object id="adoTemplate" type="Spring.Data.Generic.AdoTemplate, Spring.Data">
|
||||
<programlisting language="myxml"> <object id="adoTemplate" type="Spring.Data.Generic.AdoTemplate, Spring.Data">
|
||||
<property name="DbProvider" ref="dbProvider"/>
|
||||
<property name="DataReaderWrapperType" value="Spring.Data.Support.NullMappingDataReader, Spring.Data"/>
|
||||
</object>
|
||||
@@ -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> <object id="commandCallbackDao" type="Spring.DataQuickStart.Dao.GenericTemplate.CommandCallbackDao, Spring.DataQuickStart">
|
||||
<programlisting language="myxml"> <object id="commandCallbackDao" type="Spring.DataQuickStart.Dao.GenericTemplate.CommandCallbackDao, Spring.DataQuickStart">
|
||||
<property name="AdoTemplate" ref="adoTemplate"/>
|
||||
</object></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.
|
||||
|
||||
@@ -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><dependentAssembly>
|
||||
<programlisting language="myxml"><dependentAssembly>
|
||||
<assemblyIdentity name="MySql.Data"
|
||||
publicKeyToken="c5687fc88969c44d"
|
||||
culture="neutral"/>
|
||||
@@ -283,7 +300,7 @@
|
||||
below in the typical case of using it to specify the DbProvider property
|
||||
on an AdoTemplate.</para>
|
||||
|
||||
<programlisting><objects xmlns='http://www.springframework.net'
|
||||
<programlisting language="myxml"><objects xmlns='http://www.springframework.net'
|
||||
xmlns:db="http://www.springframework.net/database">
|
||||
|
||||
<db:provider id="DbProvider"
|
||||
@@ -302,7 +319,7 @@
|
||||
the rest of the Spring configuration locations as described in previous
|
||||
chapters.</para>
|
||||
|
||||
<programlisting><configuration>
|
||||
<programlisting language="myxml"><configuration>
|
||||
|
||||
<configSections>
|
||||
<sectionGroup name="spring">
|
||||
@@ -335,7 +352,7 @@
|
||||
|
||||
<para>An example of such a setting is shown below</para>
|
||||
|
||||
<programlisting><configuration>
|
||||
<programlisting language="myxml"><configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="spring">
|
||||
<section name='context' type='Spring.Context.Support.ContextHandler, Spring.Core'/>
|
||||
@@ -367,7 +384,7 @@
|
||||
<para>Where <literal>Dao.xml</literal> has a connection string as shown
|
||||
below</para>
|
||||
|
||||
<programlisting><objects xmlns='http://www.springframework.net'
|
||||
<programlisting language="myxml"><objects xmlns='http://www.springframework.net'
|
||||
xmlns:db="http://www.springframework.net/database">
|
||||
|
||||
<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><object id="DbProvider" type="Spring.Data.Common.UserCredentialsDbProvider, Spring.Data">
|
||||
<programlisting language="myxml"><object id="DbProvider" type="Spring.Data.Common.UserCredentialsDbProvider, Spring.Data">
|
||||
<property name="TargetDbProvider" ref="targetDbProvider"/>
|
||||
<property name="Username" value="User ID=defaultName"/>
|
||||
<property name="Password" value="Password=defaultPass"/>
|
||||
@@ -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.
|
||||
|
||||
@@ -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 <= date('1974-08-24')") //
|
||||
|
||||
ExpressionEvaluator.GetValue(null, "'Test' >= '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 > $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 > $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 <= 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 <= 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 <= 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",
|
||||
|
||||
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 10 KiB |
@@ -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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
<programlisting language="myxml"><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
<beans>
|
||||
<bean id="MyMovieLister" class="MovieFinder.MovieLister">
|
||||
<property name="finder" ref="MyMovieFinder"/>
|
||||
</bean>
|
||||
<bean id="MyMovieFinder" class="MovieFinder.SimpleMovieFinder"/>
|
||||
</beans></programlisting> Here is the corresponding file in Spring.NET
|
||||
<programlisting><objects xmlns="http://www.springframework.net"
|
||||
<programlisting language="myxml"><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">
|
||||
<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 <props> as shown below <programlisting
|
||||
format="linespecific" xml:space="preserve">
|
||||
<property name="people">
|
||||
element is name <props> as shown below
|
||||
<programlisting language="xml"><property name="people">
|
||||
<props>
|
||||
<prop key="PennAndTeller">The magic property</prop>
|
||||
<prop key="GeorgeCarlin">The funny property</prop>
|
||||
@@ -58,8 +74,7 @@
|
||||
the xml element <name-values>. The listing of the elements also
|
||||
follows the .NET convention of application configuration files using the
|
||||
<add> element with 'key' and 'value' attributes. This is show below
|
||||
<programlisting format="linespecific" xml:space="preserve">
|
||||
<property name="people">
|
||||
<programlisting language="xml"><property name="people">
|
||||
<name-values>
|
||||
<add key="PennAndTeller" value="The magic property"/>
|
||||
<add key="GeorgeCarlin" value="The funny property"/>
|
||||
@@ -67,7 +82,7 @@
|
||||
</property></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><?xml version="1.0" encoding="utf-8" ?>
|
||||
<programlisting language="myxml"><?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
|
||||
<configSections>
|
||||
@@ -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><?xml version="1.0" encoding="utf-8" ?>
|
||||
<programlisting language="myxml"><?xml version="1.0" encoding="utf-8" ?>
|
||||
<objects xmlns="http://www.springframework.net">
|
||||
<object id="target" type="Spring.Objects.TestObject">
|
||||
<property name="name" value="Bingo"/>
|
||||
@@ -219,7 +234,7 @@
|
||||
</objects></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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.<Vendor>.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->IConnection->ISession->IMessageProducer->Send</programlisting>
|
||||
<programlisting language="csharp">IConnectionFactory->IConnection->ISession->IMessageProducer->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">
|
||||
<object id="ConnectionFactory" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ">
|
||||
<constructor-arg index="0" value="tcp://localhost:61616"/>
|
||||
</object>
|
||||
@@ -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><objects xmlns="http://www.springframework.net"
|
||||
<programlisting language="myxml"><objects xmlns="http://www.springframework.net"
|
||||
xmlns:nms="http://www.springframework.net/nms">
|
||||
|
||||
<!-- other object definitions -->
|
||||
@@ -913,35 +930,35 @@ namespace MyApp
|
||||
</objects></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"><object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/></emphasis>
|
||||
<programlisting language="myxml"><object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/>
|
||||
|
||||
<object id="MessageListenerAdapter" type="Spring.Messaging.Nms.Listener.Adapter.MessageListenerAdapter, Spring.Messaging.Nms">
|
||||
<emphasis role="bold"><property name="HandlerObject" ref="MessagleHandler"/></emphasis>
|
||||
<property name="HandlerObject" ref="MessagleHandler"/>
|
||||
</object>
|
||||
|
||||
<object id="MessageListenerContainer" type="Spring.Messaging.Nms.Listener.SimpleMessageListenerContainer, Spring.Messaging.Nms">
|
||||
<property name="ConnectionFactory" ref="ConnectionFactory"/>
|
||||
<property name="DestinationName" value="APP.REQUEST"/>
|
||||
<emphasis role="bold"><property name="MessageListener" ref="MessageListenerAdapter"/></emphasis>
|
||||
<property name="MessageListener" ref="MessageListenerAdapter"/>
|
||||
</object></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"><object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/></emphasis>
|
||||
<programlisting language="myxml"><object id="MessagleHandler" type="MyApp.DefaultMessageHandler, MyApp"/>
|
||||
|
||||
<object id="MessageListenerAdapter" type="Spring.Messaging.Nms.Listener.Adapter.MessageListenerAdapter, Spring.Messaging.Nms">
|
||||
<emphasis role="bold"><property name="HandlerObject" ref="TextMessagleHandler"/></emphasis>
|
||||
<property name="HandlerObject" ref="TextMessagleHandler"/>
|
||||
<property name="DefaultHandlerMethod" value="Receive"/>
|
||||
<!-- we don't want automatic message context extraction -->
|
||||
<property name="MessageConverter">
|
||||
@@ -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 <listener/> child elements. Here is an example of a basic
|
||||
configuration for two listeners.</para>
|
||||
|
||||
<programlisting><nms:listener-container>
|
||||
<programlisting language="myxml"><nms:listener-container>
|
||||
|
||||
<nms:listener destination="queue.orders" ref="OrderService" method="PlaceOrder"/>
|
||||
|
||||
@@ -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><jms:listener-container connection-factory="MyConnectionFactory"
|
||||
<programlisting language="myxml"><jms:listener-container connection-factory="MyConnectionFactory"
|
||||
destination-resolver="MyDestinationResolver"
|
||||
concurrency="10">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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><objects xmlns='http://www.springframework.net'
|
||||
<programlisting language="myxml"><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"></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><configuration>
|
||||
<programlisting language="myxml"><configuration>
|
||||
|
||||
<configSections>
|
||||
<sectionGroup name="spring">
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
|
||||
<programlisting language="myxml"><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
|
||||
targetNamespace="http://www.springframework.net/nms/common/2008-08-05">
|
||||
|
||||
<xs:element name="TradeRequest">
|
||||
@@ -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><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
|
||||
<programlisting language="myxml"><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
|
||||
targetNamespace="http://www.springframework.net/nms/common/2008-08-05">
|
||||
|
||||
<xs:element name="TradeResponse">
|
||||
@@ -179,10 +196,10 @@
|
||||
|
||||
</xs:schema></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> <object name="XmlMessageConverter" type="Spring.NmsQuickStart.Common.Converters.XmlMessageConverter, Spring.NmsQuickStart.Common">
|
||||
<programlisting language="myxml"> <object name="XmlMessageConverter" type="Spring.NmsQuickStart.Common.Converters.XmlMessageConverter, Spring.NmsQuickStart.Common">
|
||||
<property name="TypeMapper" ref="TypeMapper"/>
|
||||
</object>
|
||||
|
||||
@@ -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> <object name="StockServiceGateway" type="Spring.NmsQuickStart.Client.Gateways.NmsStockServiceGateway, Spring.NmsQuickStart.Client">
|
||||
<property name="NmsTemplate" ref="<emphasis role="bold">NmsTemplate</emphasis>"/>
|
||||
<para>
|
||||
<programlisting language="myxml"> <object name="StockServiceGateway" type="Spring.NmsQuickStart.Client.Gateways.NmsStockServiceGateway, Spring.NmsQuickStart.Client">
|
||||
<property name="NmsTemplate" ref="NmsTemplate"/>
|
||||
<property name="DefaultReplyToQueue">
|
||||
<object type="Apache.NMS.ActiveMQ.Commands.ActiveMQQueue, Apache.NMS.ActiveMQ">
|
||||
<constructor-arg value="APP.STOCK.JOE"/>
|
||||
@@ -370,32 +388,32 @@
|
||||
</property>
|
||||
</object>
|
||||
|
||||
<object name="<emphasis role="bold">NmsTemplate</emphasis>" type="Spring.Messaging.Nms.Core.NmsTemplate, Spring.Messaging.Nms">
|
||||
<property name="ConnectionFactory" ref="<emphasis role="bold">ConnectionFactory</emphasis>"/>
|
||||
<object name="NmsTemplate" type="Spring.Messaging.Nms.Core.NmsTemplate, Spring.Messaging.Nms">
|
||||
<property name="ConnectionFactory" ref="ConnectionFactory"/>
|
||||
<property name="DefaultDestinationName" value="APP.STOCK.REQUEST"/>
|
||||
<property name="MessageConverter" ref="XmlMessageConverter"/>
|
||||
</object>
|
||||
|
||||
<object id="<emphasis role="bold">ConnectionFactory</emphasis>" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ">
|
||||
<object id="ConnectionFactory" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ">
|
||||
<constructor-arg index="0" value="tcp://localhost:61616"/>
|
||||
</object></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> <nms:listener-container connection-factory="ConnectionFactory">
|
||||
<programlisting language="myxml"> <nms:listener-container connection-factory="ConnectionFactory">
|
||||
<nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.JOE" />
|
||||
<nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.MARKETDATA" pubsub-domain="true"/>
|
||||
</nms:listener-container></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> <nms:listener-container connection-factory="ConnectionFactory" concurrency="<emphasis
|
||||
<programlisting language="myxml"> <nms:listener-container connection-factory="ConnectionFactory" concurrency="<emphasis
|
||||
role="bold">10</emphasis>">
|
||||
<nms:listener ref="MessageListenerAdapter" destination="APP.STOCK.REQUEST" />
|
||||
</nms:listener-container></programlisting>
|
||||
|
||||
@@ -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><objects xmlns="http://www.springframework.net">
|
||||
<literal>Type</literal> instance for use in this factory-style class.
|
||||
<programlisting language="myxml"><objects xmlns="http://www.springframework.net">
|
||||
<object id="parserFactory" type="Example.XmlParserFactory, ExamplesLibrary"
|
||||
destroy-method="Close">
|
||||
<property name="ParserClass" value="Example.Xml.SAXParser, ExamplesLibrary"/>
|
||||
</object>
|
||||
</objects></programlisting> <programlisting>[C#]
|
||||
</objects></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><object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<programlisting language="myxml"><object id="rod" type="Spring.Objects.TestObject, Spring.Core.Tests">
|
||||
<property name="name" value="Rod"/>
|
||||
<property name="FileMode" value="Create"/>
|
||||
</object></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>
|
||||
|
||||
|
||||
@@ -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> <object id="HibernateTransactionManager"
|
||||
<programlisting language="myxml"> <object id="HibernateTransactionManager"
|
||||
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate">
|
||||
|
||||
<property name="DbProvider" ref="DbProvider"/>
|
||||
@@ -210,14 +227,14 @@
|
||||
</object></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><objects xmlns="http://www.springframework.net"
|
||||
<programlisting language="myxml"><objects xmlns="http://www.springframework.net"
|
||||
xmlns:db="http://www.springframework.net/database">
|
||||
|
||||
|
||||
@@ -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><objects>
|
||||
<programlisting language="myxml"><objects>
|
||||
|
||||
<object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate">
|
||||
<property name="SessionFactory" ref="MySessionFactory"/>
|
||||
@@ -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<Supplier> suppliers = HibernateTemplate.ExecuteFind<Supplier>(
|
||||
<programlisting language="csharp">IList<Supplier> suppliers = HibernateTemplate.ExecuteFind<Supplier>(
|
||||
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">
|
||||
<objects>
|
||||
|
||||
<object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate">
|
||||
@@ -602,9 +619,9 @@ public class HibernateCustomerDao : ICustomerDao {
|
||||
|
||||
<para>The first way is shown below</para>
|
||||
|
||||
<programlisting><object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
|
||||
<programlisting language="myxml"><object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
|
||||
|
||||
<emphasis role="bold"><property name="ExposeTransactionAwareSessionFactory" value="true" /></emphasis>
|
||||
<property name="ExposeTransactionAwareSessionFactory" value="true" />
|
||||
|
||||
<!-- other configuration settings omitted -->
|
||||
|
||||
@@ -612,7 +629,7 @@ public class HibernateCustomerDao : ICustomerDao {
|
||||
|
||||
<para>Which is simply a shortcut for the following configuration</para>
|
||||
|
||||
<programlisting><object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
|
||||
<programlisting language="myxml"><object id="sessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
|
||||
|
||||
<!-- other configuration settings omitted -->
|
||||
|
||||
@@ -621,8 +638,8 @@ public class HibernateCustomerDao : ICustomerDao {
|
||||
|
||||
<!-- other dictionary entries omitted -->
|
||||
|
||||
<emphasis role="bold"><entry key="hibernate.current_session_context_class"
|
||||
value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12"/></emphasis>
|
||||
<entry key="hibernate.current_session_context_class"
|
||||
value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12"/>
|
||||
|
||||
</dictionary>
|
||||
</property>
|
||||
@@ -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><objects>
|
||||
<programlisting language="myxml"><objects>
|
||||
|
||||
TO BE DONE
|
||||
|
||||
</objects></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><objects>
|
||||
<programlisting language="myxml"><objects>
|
||||
|
||||
<object id="HibernateTransactionManager"
|
||||
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate">
|
||||
@@ -740,7 +757,7 @@ TO BE DONE
|
||||
expresses the intent as compared to the contents of
|
||||
DeclarativeServicesAttributeDriven.xml.</para>
|
||||
|
||||
<programlisting><objects xmlns="http://www.springframework.net"
|
||||
<programlisting language="myxml"><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 <tx:attribute-driven/></para>
|
||||
|
||||
<programlisting> <object id="TxProxyConfigurationTemplate" abstract="true"
|
||||
<programlisting language="myxml"> <object id="TxProxyConfigurationTemplate" abstract="true"
|
||||
type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
|
||||
|
||||
<property name="PlatformTransactionManager" ref="HibernateTransactionManager"/>
|
||||
@@ -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> <system.web>
|
||||
<programlisting language="myxml"> <system.web>
|
||||
<httpModules>
|
||||
<add name="OpenSessionInView" type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, Spring.Data.NHibernate"/>
|
||||
</httpModules>
|
||||
@@ -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> <appSettings>
|
||||
<programlisting language="myxml"> <appSettings>
|
||||
<add key="Spring.Data.NHibernate.Support.OpenSessionInViewModule.SessionFactoryObjectName" value="SessionFactory"/>
|
||||
</appSettings></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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 < 3)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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> <object name="exampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz">
|
||||
<programlisting language="myxml"> <object name="exampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz">
|
||||
<property name="JobType" value="Spring.Scheduling.Quartz.Example.ExampleJob, Spring.Scheduling.Quartz.Example" />
|
||||
<!-- We can inject values through JobDataMap -->
|
||||
<property name="JobDataAsMap">
|
||||
@@ -99,18 +116,18 @@
|
||||
</object></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> <object id="cronTrigger" type="Spring.Scheduling.Quartz.CronTriggerObject, Spring.Scheduling.Quartz">
|
||||
<programlisting language="myxml"> <object id="cronTrigger" type="Spring.Scheduling.Quartz.CronTriggerObject, Spring.Scheduling.Quartz">
|
||||
<property name="jobDetail" ref="exampleJob" />
|
||||
<!-- run every 20 second of minute -->
|
||||
<property name="cronExpressionString" value="0/20 * * * * ?" />
|
||||
@@ -119,7 +136,7 @@
|
||||
<para>Lastly, we schedule this trigger with the scheduler as shown
|
||||
below</para>
|
||||
|
||||
<programlisting> <object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
|
||||
<programlisting language="myxml"> <object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
|
||||
<property name="triggers">
|
||||
<list>
|
||||
<ref object="cronTrigger" />
|
||||
@@ -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> <object id="adminService" type="Spring.Scheduling.Quartz.Example.AdminService, Spring.Scheduling.Quartz.Example">
|
||||
<programlisting language="myxml"> <object id="adminService" type="Spring.Scheduling.Quartz.Example.AdminService, Spring.Scheduling.Quartz.Example">
|
||||
<!-- we inject straight to target object -->
|
||||
<property name="UserName" value="admin-service" />
|
||||
</object>
|
||||
@@ -174,14 +191,14 @@
|
||||
</object>
|
||||
</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> <object id="simpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz">
|
||||
<programlisting language="myxml"> <object id="simpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz">
|
||||
<!-- see the example of method invoking job above -->
|
||||
<property name="jobDetail" ref="jobDetail" />
|
||||
<!-- 5 seconds -->
|
||||
@@ -200,7 +217,7 @@
|
||||
<para>This trigger can then be added to the scheduler's list of registered
|
||||
triggers as shown below.</para>
|
||||
|
||||
<programlisting> <object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
|
||||
<programlisting language="myxml"> <object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
|
||||
<property name="triggers">
|
||||
<list>
|
||||
<ref object="cronTrigger" />
|
||||
|
||||
@@ -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><?xml version="1.0" encoding="utf-8" ?>
|
||||
<programlisting language="myxml"><?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="spring">
|
||||
@@ -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><objects/></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><objects xmlns="http://www.springframework.net">
|
||||
<programlisting language="myxml"><objects xmlns="http://www.springframework.net">
|
||||
<object name="MyMovieLister"
|
||||
type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
|
||||
</object>
|
||||
@@ -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><objects xmlns="http://www.springframework.net">
|
||||
<programlisting language="myxml"><objects xmlns="http://www.springframework.net">
|
||||
<object name="MyMovieFinder"
|
||||
type="Spring.Examples.MovieFinder.SimpleMovieFinder, Spring.Examples.MovieFinder"/>
|
||||
</object>
|
||||
</objects></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><objects xmlns="http://www.springframework.net">
|
||||
Setter Injection and the following XML... <programlisting language="myxml"><objects xmlns="http://www.springframework.net">
|
||||
<object name="MyMovieLister"
|
||||
type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
|
||||
<!-- using setter injection... -->
|
||||
@@ -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">...
|
||||
<object name="AnotherMovieFinder"
|
||||
type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder, Spring.Examples.MovieFinder">
|
||||
</object>
|
||||
@@ -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">...
|
||||
<object name="AnotherMovieFinder"
|
||||
type="Spring.Examples.MovieFinder.ColonDelimitedMovieFinder, Spring.Examples.MovieFinder">
|
||||
<constructor-arg index="0" value="movies.txt"/>
|
||||
@@ -269,11 +269,11 @@ using Spring.Context;
|
||||
<para>Unsurprisingly, the <constructor-arg/> 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">...
|
||||
<object name="MyMovieLister"
|
||||
type="Spring.Examples.MovieFinder.MovieLister, Spring.Examples.MovieFinder">
|
||||
<!-- lets use the colon delimited implementation instead -->
|
||||
@@ -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><section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /></programlisting>
|
||||
The corresponding configuration section looks like this <programlisting>
|
||||
as shown below <programlisting language="myxml"><section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /></programlisting>
|
||||
The corresponding configuration section looks like this <programlisting language="myxml">
|
||||
<log4net>
|
||||
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
@@ -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">...
|
||||
<object name="messageSource" type="Spring.Context.Support.ResourceSetMessageSource, Spring.Core">
|
||||
<property name="resourceManagers">
|
||||
<list>
|
||||
@@ -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.<PropertyName>. 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
|
||||
|
||||
@@ -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><system.runtime.remoting>
|
||||
<programlisting language="myxml"><system.runtime.remoting>
|
||||
<application>
|
||||
<channels>
|
||||
<channel ref="tcp" port="8005" />
|
||||
@@ -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> <configSections>
|
||||
<programlisting language="myxml"> <configSections>
|
||||
<sectionGroup name="spring">
|
||||
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
|
||||
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
|
||||
@@ -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><objects
|
||||
below.<programlisting language="myxml"><objects
|
||||
xmlns="http://www.springframework.net"
|
||||
xmlns:r="http://www.springframework.net/remoting">
|
||||
|
||||
@@ -334,16 +351,16 @@ public class AdvancedCalculator : Calculator, IAdvancedCalculator
|
||||
serviceName="RemotedSaoSingletonCalculator" />
|
||||
</objects></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><object name="saoSingletonCalculator" type="Spring.Remoting.SaoExporter, Spring.Services">
|
||||
configuration shown below.<programlisting language="myxml"><object name="saoSingletonCalculator" type="Spring.Remoting.SaoExporter, Spring.Services">
|
||||
<property name="TargetName" value="singletonCalculator" />
|
||||
<property name="ServiceName" value="RemotedSaoSingletonCalculator" />
|
||||
</object></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><system.runtime.remoting>
|
||||
<programlisting language="myxml"><system.runtime.remoting>
|
||||
<application>
|
||||
<channels>
|
||||
<channel ref="tcp"/>
|
||||
@@ -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">
|
||||
<spring>
|
||||
<context>
|
||||
<resource uri="config://spring/objects" />
|
||||
@@ -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">
|
||||
<objects xmlns="http://www.springframework.net">
|
||||
|
||||
<description>inProcess</description>
|
||||
@@ -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><objects xmlns="http://www.springframework.net">
|
||||
implementation is shown below <programlisting language="myxml"><objects xmlns="http://www.springframework.net">
|
||||
|
||||
<description>saoSingleton</description>
|
||||
|
||||
@@ -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><property name="ServiceUrl" value="${protocol}://${host}:${port}/RemotedSaoSingletonCalculator" /></programlisting>
|
||||
<programlisting language="myxml"><property name="ServiceUrl" value="${protocol}://${host}:${port}/RemotedSaoSingletonCalculator" /></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><objects xmlns="http://www.springframework.net">
|
||||
exported CAO implementation is shown below <programlisting language="myxml"><objects xmlns="http://www.springframework.net">
|
||||
|
||||
<description>cao</description>
|
||||
|
||||
@@ -558,7 +575,7 @@ Memory = 2
|
||||
definitions which should give you a good feel for how to use the
|
||||
schema.</para>
|
||||
|
||||
<programlisting><!-- Calculator definitions -->
|
||||
<programlisting language="myxml"><!-- Calculator definitions -->
|
||||
<object id="singletonCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services">
|
||||
<constructor-arg type="int" value="217" />
|
||||
</object>
|
||||
@@ -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> <spring>
|
||||
<programlisting language="myxml"> <spring>
|
||||
|
||||
<context>
|
||||
<resource uri="config://spring/objects" />
|
||||
@@ -625,7 +642,7 @@ Memory = 2
|
||||
AccessControl and Roles properties. The configuration file for
|
||||
enterpriseServices.xml is shown below</para>
|
||||
|
||||
<para><programlisting><objects xmlns="http://www.springframework.net">
|
||||
<para><programlisting language="myxml"><objects xmlns="http://www.springframework.net">
|
||||
|
||||
<description>enterpriseService</description>
|
||||
|
||||
@@ -681,7 +698,7 @@ Memory = 2
|
||||
</objects></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> <context>
|
||||
<programlisting language="myxml"> <context>
|
||||
<resource uri="config://spring/objects"/>
|
||||
<resource uri="~/Config/webServices.xml"/>
|
||||
<resource uri="~/Config/webServices-aop.xml"/>
|
||||
@@ -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> <objects xmlns="http://www.springframework.net">
|
||||
These definitions are shown below<programlisting language="myxml"> <objects xmlns="http://www.springframework.net">
|
||||
|
||||
<!-- Aspect -->
|
||||
|
||||
@@ -724,7 +741,7 @@ Memory = 2
|
||||
</objects></programlisting>The configuration file webService.xml
|
||||
simply exports the named calculator object</para>
|
||||
|
||||
<programlisting> <object id="calculatorService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
|
||||
<programlisting language="myxml"> <object id="calculatorService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
|
||||
<property name="TargetName" value="calculator" />
|
||||
<property name="Namespace" value="http://SpringCalculator/WebServices" />
|
||||
<property name="Description" value="Spring Calculator Web Services" />
|
||||
@@ -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> <object id="calculatorServiceWeaved" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
|
||||
<programlisting language="myxml"> <object id="calculatorServiceWeaved" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
|
||||
<property name="TargetName" value="calculatorWeaved" />
|
||||
<property name="Namespace" value="http://SpringCalculator/WebServices" />
|
||||
<property name="Description" value="Spring Calculator Web Services" />
|
||||
@@ -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
|
||||
|
||||
@@ -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><object id="singletonCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services">
|
||||
<programlisting language="myxml"><object id="singletonCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services">
|
||||
<constructor-arg type="int" value="217"/>
|
||||
</object>
|
||||
|
||||
@@ -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><objects xmlns="http://www.springframework.net"
|
||||
below<programlisting language="myxml"><objects xmlns="http://www.springframework.net"
|
||||
xmlns:r="http://www.springframework.net/remoting">
|
||||
|
||||
<r:saoExporter targetName="singletonCalculator"
|
||||
@@ -106,12 +123,12 @@ RemotingServices.Marshal(calc, "MyRemotedCalculator");</programlisting></para>
|
||||
</objects></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><object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
|
||||
service in SAO 'SingleCall' mode. <programlisting language="myxml"><object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
|
||||
singleton="false">
|
||||
<constructor-arg type="int" value="217"/>
|
||||
</object>
|
||||
@@ -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><object id="singletonCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
|
||||
<programlisting language="myxml"><object id="singletonCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
|
||||
<property name="target" ref="singletonCalculator"/>
|
||||
<property name="interceptorNames">
|
||||
<list>
|
||||
@@ -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><system.runtime.remoting>
|
||||
<programlisting language="myxml"><system.runtime.remoting>
|
||||
<application>
|
||||
<channels>
|
||||
<channel ref="tcp" port="8005" />
|
||||
@@ -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><objects xmlns="http://www.springframework.net"
|
||||
<programlisting language="myxml"><objects xmlns="http://www.springframework.net"
|
||||
xmlns:r="http://www.springframework.net/remoting">
|
||||
|
||||
<r:configurer filename="Spring.Calculator.RemoteApp.exe.config" />
|
||||
@@ -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><object id="calculatorService" type="Spring.Remoting.SaoFactoryObject, Spring.Services">
|
||||
<programlisting language="myxml"><object id="calculatorService" type="Spring.Remoting.SaoFactoryObject, Spring.Services">
|
||||
<property name="ServiceInterface" value="Spring.Calculator.Interfaces.IAdvancedCalculator, Spring.Calculator.Contract" />
|
||||
<property name="ServiceUrl" value="tcp://localhost:8005/RemotedSaoSingletonCalculator" />
|
||||
</object></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><object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
|
||||
<para><programlisting language="myxml"><object id="prototypeCalculator" type="Spring.Calculator.Services.AdvancedCalculator, Spring.Calculator.Services"
|
||||
singleton="false">
|
||||
<constructor-arg type="int" value="217" />
|
||||
</object></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><object id="caoCalculator" type="Spring.Remoting.CaoExporter, Spring.Services">
|
||||
<programlisting language="myxml"><object id="caoCalculator" type="Spring.Remoting.CaoExporter, Spring.Services">
|
||||
<property name="TargetName" value="prototypeCalculator" />
|
||||
<property name="Infinite" value="false" />
|
||||
<property name="InitialLeaseTime" value="2m" />
|
||||
@@ -372,7 +389,7 @@ Console.ReadLine();
|
||||
<para>Alternatively, you can use the remoting schema and declare the CAO
|
||||
object as shown below</para>
|
||||
|
||||
<programlisting><r:caoExporter targetName="prototypeCalculator" infinite="false">
|
||||
<programlisting language="myxml"><r:caoExporter targetName="prototypeCalculator" infinite="false">
|
||||
<r:lifeTime initialLeaseTime="2m" renewOnCallTime="1m" />
|
||||
</r:caoExporter></programlisting>
|
||||
|
||||
@@ -386,7 +403,7 @@ Console.ReadLine();
|
||||
from the Remoting QuickStart, a calculator with logging around advice is
|
||||
defined as shown below.</para>
|
||||
|
||||
<programlisting><object id="prototypeCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
|
||||
<programlisting language="myxml"><object id="prototypeCalculatorWeaved" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
|
||||
<property name="targetSource">
|
||||
<object type="Spring.Aop.Target.PrototypeTargetSource, Spring.Aop">
|
||||
<property name="TargetObjectName" value="prototypeCalculator" />
|
||||
@@ -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><r:caoExporter targetName="prototypeCalculatorWeaved" infinite="false">
|
||||
<programlisting language="myxml"><r:caoExporter targetName="prototypeCalculatorWeaved" infinite="false">
|
||||
<r:lifeTime initialLeaseTime="2m" renewOnCallTime="1m" />
|
||||
</r:caoExporter></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><object id="calculatorService" type="Spring.Remoting.CaoFactoryObject, Spring.Services">
|
||||
<programlisting language="myxml"><object id="calculatorService" type="Spring.Remoting.CaoFactoryObject, Spring.Services">
|
||||
<property name="RemoteTargetName" value="prototypeCalculator" />
|
||||
<property name="ServiceUrl" value="tcp://localhost:8005" />
|
||||
</object></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><r:caoFactory id="calculatorService"
|
||||
<programlisting language="myxml"><r:caoFactory id="calculatorService"
|
||||
remoteTargetName="prototypeCalculator"
|
||||
serviceUrl="tcp://localhost:8005" /></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
|
||||
|
||||
@@ -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><configuration>
|
||||
<programlisting language="myxml"><configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="spring">
|
||||
|
||||
<section name='context' type='Spring.Context.Support.ContextHandler, Spring.Core'/>
|
||||
|
||||
<emphasis role="bold"> <section name="resourceHandlers"
|
||||
type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/></emphasis>
|
||||
<section name="resourceHandlers"
|
||||
type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/>
|
||||
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
|
||||
<spring>
|
||||
|
||||
<emphasis role="bold"> <resourceHandlers>
|
||||
<resourceHandlers>
|
||||
<handler protocol="db" type="MyCompany.MyApp.Resources.MyDbResource, MyAssembly"/>
|
||||
</resourceHandlers></emphasis>
|
||||
</resourceHandlers>
|
||||
|
||||
<context>
|
||||
<resource uri="db://user:pass@dbName/MyDefinitionsTable"/>
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
<object name="ExampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz">
|
||||
<property name="JobType" value="Example.Quartz.ExampleJob, Example.Quartz" />
|
||||
<property name="JobDataAsMap">
|
||||
@@ -46,17 +63,17 @@
|
||||
</object></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><object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz">
|
||||
<programlisting language="myxml"><object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz">
|
||||
<property name="TargetObject" ref="ExampleBusinessObject" />
|
||||
<property name="TargetMethod" value="DoIt" />
|
||||
</object></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">
|
||||
<object id="ExampleBusinessObject" type="Examples.BusinessObjects.ExampleBusinessObject, Examples.BusinessObjects"/></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><object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz">
|
||||
<programlisting language="myxml"><object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz">
|
||||
<property name="TargetObject" ref="ExampleBusinessObject" />
|
||||
<property name="TargetMethod" value="DoIt" />
|
||||
<property name="Concurrent" value="false" />
|
||||
@@ -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><object id="SimpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz">
|
||||
<programlisting language="myxml"><object id="SimpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz">
|
||||
<!-- see the example of method invoking job above -->
|
||||
<property name="JobDetail" ref="ExampleJob" />
|
||||
|
||||
@@ -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><object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
|
||||
<programlisting language="myxml"><object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz">
|
||||
<property name="triggers">
|
||||
<list>
|
||||
<ref object="CronTrigger" />
|
||||
@@ -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
|
||||
|
||||
@@ -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><object id="userManager" type="MyApp.Services.SimpleUserManager">
|
||||
<programlisting language="myxml"><object id="userManager" type="MyApp.Services.SimpleUserManager">
|
||||
<property name="UserDao" ref="userDao"/>
|
||||
</object></programlisting>
|
||||
|
||||
@@ -125,7 +142,7 @@
|
||||
to export our service using the exporter
|
||||
<literal>ServicedComponentExporter</literal> as shown below</para>
|
||||
|
||||
<programlisting><object id="MyApp.EnterpriseServices.UserManager" type="Spring.Enterprise.ServicedComponentExporter, Spring.Services">
|
||||
<programlisting language="myxml"><object id="MyApp.EnterpriseServices.UserManager" type="Spring.Enterprise.ServicedComponentExporter, Spring.Services">
|
||||
<property name="TargetName" value="userManager"/>
|
||||
<property name="TypeAttributes">
|
||||
<list>
|
||||
@@ -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><object id="MyComponentExporter" type="Spring.Enterprise.EnterpriseServicesExporter, Spring.Services">
|
||||
<programlisting language="myxml"><object id="MyComponentExporter" type="Spring.Enterprise.EnterpriseServicesExporter, Spring.Services">
|
||||
<property name="ApplicationName" value="My COM+ Application"/>
|
||||
<property name="Description" value="My enterprise services application."/>
|
||||
<property name="AccessControl">
|
||||
@@ -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><object id="enterpriseUserManager" type="Spring.Enterprise.ServicedComponentFactory, Spring.Services">
|
||||
<programlisting language="myxml"><object id="enterpriseUserManager" type="Spring.Enterprise.ServicedComponentFactory, Spring.Services">
|
||||
<property name="Name" value="MyApp.EnterpriseServices.UserManager"/>
|
||||
<property name="Template" value="userManager"/>
|
||||
</object></programlisting>
|
||||
|
||||
@@ -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><spring>
|
||||
<programlisting language="myxml"><spring>
|
||||
<parsers>
|
||||
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" />
|
||||
</parsers>
|
||||
@@ -142,7 +159,7 @@
|
||||
<para>The XML configuration to configure the TripForm form is shown
|
||||
below</para>
|
||||
|
||||
<programlisting> <object type="TripForm.aspx" parent="standardPage">
|
||||
<programlisting language="myxml"> <object type="TripForm.aspx" parent="standardPage">
|
||||
<property name="BookingAgent" ref="bookingAgent" />
|
||||
<property name="AirportDao" ref="airportDao" />
|
||||
<property name="TripValidator" ref="tripValidator" />
|
||||
@@ -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> <v:group id="tripValidator">
|
||||
<programlisting language="myxml"> <v:group id="tripValidator">
|
||||
|
||||
<v:required id="departureAirportValidator" test="StartingFrom.AirportCode">
|
||||
<v:message id="error.departureAirport.required" providers="departureAirportErrors, validationSummary"/>
|
||||
@@ -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> <object id="bookingAgentWebService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
|
||||
<programlisting language="myxml"> <object id="bookingAgentWebService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
|
||||
<property name="TargetName" value="bookingAgent"/>
|
||||
<property name="Name" value="BookingAgent"/>
|
||||
<property name="Namespace" value="http://SpringAir/WebServices"/>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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><runtime>
|
||||
<programlisting language="myxml"><runtime>
|
||||
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
|
||||
@@ -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><?xml version="1.0" encoding="utf-8" ?>
|
||||
<programlisting language="myxml"><?xml version="1.0" encoding="utf-8" ?>
|
||||
<objects xmlns="http://www.springframework.net">
|
||||
|
||||
<lineannotation><!-- this object will be injected into the <classname>HibernateTitleDaoTests</classname> class --></lineannotation>
|
||||
<lineannotation><!-- this object will be injected into the <literal>HibernateTitleDaoTests</literal> class --></lineannotation>
|
||||
<object id="titleDao" type="Spring.Samples.HibernateTitleDao, Spring.Samples">
|
||||
<property name="sessionFactory" ref="sessionFactory"/>
|
||||
</object>
|
||||
@@ -249,7 +266,7 @@ public class HibernateTitleDaoTests <emphasis role="bold">: AbstractDependencyIn
|
||||
</objects></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
|
||||
|
||||