fixes for daily build target

misc updates to ref documentation
use signed NNS assembly based on spring.net key
sync vs.net 2003 solution
This commit is contained in:
markpollack
2008-06-17 02:13:28 +00:00
parent d56ad5a9dc
commit fc584813bb
16 changed files with 664 additions and 962 deletions

View File

@@ -67,6 +67,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Data.NHibernate12.20
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Messaging.Nms.2003", "src\Spring\Spring.Messaging.Nms\Spring.Messaging.Nms.2003.csproj", "{C17B27C2-4343-45BA-9A21-73C3CEC19BAD}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
@@ -213,6 +217,14 @@ Global
{2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Release.Build.0 = Release|.NET
{2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Release-1.1.ActiveCfg = Release|.NET
{2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Release-1.1.Build.0 = Release|.NET
{C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Debug.ActiveCfg = Debug|.NET
{C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Debug.Build.0 = Debug|.NET
{C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Debug-1.1.ActiveCfg = Debug|.NET
{C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Debug-1.1.Build.0 = Debug|.NET
{C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Release.ActiveCfg = Release|.NET
{C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Release.Build.0 = Release|.NET
{C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Release-1.1.ActiveCfg = Release|.NET
{C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Release-1.1.Build.0 = Release|.NET
EndGlobalSection
GlobalSection(SolutionItems) = postSolution
doc\NamespaceSummary.xml = doc\NamespaceSummary.xml

View File

@@ -199,6 +199,7 @@
<call target="compile-build-1.0"/>
<call target="compile-build-1.1"/>
<call target="compile-build-2.0"/>
<!-- Ignore Compact Framework 1.0 for now -->
<!-- call target="compile-build-netcf-1.0"/ -->
@@ -309,7 +310,7 @@
<nant buildfile="src/Spring/Spring.Data.NHibernate20/Spring.Data.NHibernate20.build" target="build" if="${build-data and (nant.settings.currentframework == 'net-2.0')}"/>
<nant buildfile="src/Spring/Spring.Services/Spring.Services.build" target="build" if="${build-services}"/>
<nant buildfile="src/Spring/Spring.Testing.NUnit/Spring.Testing.NUnit.build" target="build" if="${build-testing}"/>
<nant buildfile="src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.build" target="build" if="${build-web}"/>
<nant buildfile="src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.build" target="build" if="${build-nms}"/>
<!-- build examples -->
@@ -324,7 +325,7 @@
<nant buildfile="test/Spring/Spring.Data.NHibernate.Tests/Spring.Data.NHibernate.Tests.build" target="test" if="${build-data and (nant.settings.currentframework == 'net-1.1' or nant.settings.currentframework == 'net-2.0')}"/>
<nant buildfile="test/Spring/Spring.Data.NHibernate.Integration.Tests/Spring.Data.NHibernate.Integration.Tests.build" target="test" if="${build-data and (nant.settings.currentframework == 'net-1.1' or nant.settings.currentframework == 'net-2.0')}"/>
<nant buildfile="test/Spring/Spring.Services.Tests/Spring.Services.Tests.build" target="test" if="${build-services}"/>
<nant buildfile="test/Spring/Spring.Web.Tests/Spring.Web.Tests.build" target="test" if="${build-web}"/>
<nant buildfile="test/Spring/Spring.Web.Tests/Spring.Web.Tests.build" target="test" if="${build-nms}"/>
<nant buildfile="test/Spring/Spring.Testing.NUnit.Tests/Spring.Testing.NUnit.Tests.build" target="test"/>
<nant buildfile="test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.build" target="test" if="false"/>
</target>
@@ -336,6 +337,7 @@
<call target="common.generate-assemblyinfo"/>
<!-- disable namespaces not supported in net-1.0 -->
<property name="build-web" value="false" />
<property name="build-nms" value="false" />
<call target="compile-test" />
</target>
@@ -343,6 +345,7 @@
depends="set-net-1.1-runtime-configuration, check-spring-basedir, clean-current-bin-dir, TestInit">
<call target="copykeys" if="${project.build.sign}"/>
<call target="common.generate-assemblyinfo"/>
<property name="build-nms" value="false" />
<call target="compile-test" />
</target>
@@ -350,6 +353,7 @@
depends="set-net-2.0-runtime-configuration, check-spring-basedir, clean-current-bin-dir, TestInit">
<call target="copykeys" if="${project.build.sign}"/>
<call target="common.generate-assemblyinfo"/>
<property name="build-nms" value="true" />
<call target="compile-test" />
</target>
@@ -644,10 +648,8 @@
<target name="build-all-function" description="Build what is in cvs taking into account approrpiate clr versions and root target name">
<call target="${nant.target.root.name}-1.0" />
<call target="${nant.target.root.name}-1.0" />
<call target="${nant.target.root.name}-1.1" />
<call target="${nant.target.root.name}-2.0" />
<!-- ignore Mono 2.0 for now -->
@@ -695,18 +697,6 @@
<tstamp/>
<property name="package.version" value="${tstamp.date}-${tstamp.time}"/>
<!--
<call target="set-build-namespaces-all"/>
<call target="set-package-configuration"/>
<call target="clean-current-package-dir"/>
<call target="set-debug-build-configuration"/>
<call target="compile-build"/>
<call target="set-release-build-configuration"/>
<call target="compile-build"/>
-->
<call target="prepare-docs"/>
<exec workingdir="./doc" program="cmd.exe" commandline="/c ant refdoc"/>
@@ -778,7 +768,6 @@
<target name="upload-cvs-release">
<call target="set-package-configuration"/>
<property name="filetoupload" value="${project.name}-${package.version}.zip"/>
<property name="spring.ssh.server" value="spring02.managed.contegix.com" />
<property name="spring.ssh.user" value="markp"/>
<property name="spring.ssh.args" value=" -l ${spring.ssh.user} " />
@@ -870,6 +859,8 @@
<include name="**/Spring.Testing.NUnit.xml"/>
<include name="**/Spring.Testing.NUnit.pdb"/>
<include name="**/Spring.Messaging.Nms.dll"/>
<include name="**/antlr.runtime.dll"/>
<include name="**/Common.Logging.dll"/>
<include name="**/Common.Logging.*.dll"/>
@@ -947,6 +938,8 @@
<include name="**/NUnitAspEx.dll"/>
<include name="**/Rhino.Mocks.dll"/>
<include name="**/System.Web.Extensions.dll"/>
<include name="**/Apache.NMS.dll"/>
<include name="**/Apache.NMS.MSMQ.dll"/>
<include name="**/EULA.rtf"/>
</fileset>
</copy>
@@ -1016,7 +1009,7 @@
file="src/Spring/Spring.Services/Remoting/Config/spring-remoting-1.1.xsd"/>
<copy todir="${current.package.dir}/doc/schema"
file="doc/install-schema.build"/>
file="build-support/install-schema.build"/>
<echo message="copying source code for release..."/>

View File

@@ -54,7 +54,7 @@
<title>The Spring.NET Framework</title>
<subtitle>Reference Documentation</subtitle>
<releaseinfo>Version 1.1.2</releaseinfo>
<pubdate>Last Updated May 6, 2008</pubdate>
<pubdate>Last Updated June 12, 2008</pubdate>
<authorgroup>
<author>
<firstname>Mark</firstname>
@@ -288,6 +288,7 @@
&services;
&webservices;
</part>
<!--
<part id="spring-integration">
<title>Integration</title>
<partintro id="spring-integration-intro">
@@ -305,9 +306,10 @@
</listitem>
</itemizedlist>
</partintro>
&jms;
&nms;
&scheduling;
</part>
-->
<part id="index-vsnet">
<title>VS.NET Integration</title>
<partintro>

View File

@@ -1,441 +0,0 @@
<%@ CodeTemplate %>
<%@ Assembly Name="System.Web" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Text" %>
<%@ Assembly Name="AgileDocs.Core" %>
<%@ Import Namespace="AgileDocs.Core" %>
<script runat="template">
string XmlExample (string fileName, string xpath)
{
return "<programlisting format='linespecific'>"
+ XmlPeek.HtmlEncode (
XmlPeek.ExtractAndQueryXPath(fileName, xpath,
new ExtractXml("<!--@", "@-->")))
+ "</programlisting>";
}
string CsExample (string fileName, string xpath)
{
return "<programlisting format='linespecific'>"
+ XmlPeek.HtmlEncode (
XmlPeek.ExtractAndQueryXPath(fileName, xpath,
new ExtractXml("////", null)))
+ "</programlisting>";
}
string EntireFile (string fileName)
{
return "<programlisting format='linespecific'>"
+ XmlPeek.HtmlEncode (
XmlPeek.GetFileContent(fileName))
+ "</programlisting>";
}
</script>
<chapter id="windows-service">
<title>Windows Services</title>
<sect1>
<title>Remarks</title>
<para>
This is functionality that will be included after the
1.0 release. If you want to use these features please get the
code from CVS <ulink url="http://opensource.atlassian.com/confluence/spring/display/NET/Project+Structure"></ulink>
(instructions) or from the download section of the Spring.NET website that contains an
.zip with the full CVS tree.
In addition to this documentation
you can refer to the example program located at
<literal>examples\Spring\Spring.Examples.WindowsService</literal>
to better understand the package. Please check the Spring.NET
<ulink url="http://www.springframework.net/doc/reference/windows-service.html">website</ulink>
for the latest updates to this document.
</para>
</sect1>
<sect1>
<title>Introduction</title>
<para>
Developers usually create Windows Services using the
Visual Studio .NET wizard. While not difficult to do, this
procedure is repetative and does not encourage separation between
infrastructure code (windows service) and application code. This is
generally considered a "bad thing" but you can certainly disagree.
</para>
<para>
As Spring.NET can provide an explicitly managed
initialize/destroy lifecycle for singleton objects, there is
a natural synergy with the lifecycle of a Windows service.
As such, it could be very convenient to expose a Spring application
context as a Windows service. Starting and stopping the service corresponds
to creating and destroying an application context and its
contained objects. This approach provides a high level means to
declare what objects are created and destroyed when developing
a Windows service.
</para>
<para>
To do that, Spring.NET requires the installation of one physical
service able to run as services as many applications as you want - each a
logical independent service in their own application domain.
By default, the deployment and updating of the service can also
be done by copying the relevant executables to a special directory.
</para>
<para>
The executable that at present provides these features is the
<literal>Spring.Services.WindowsService.Process.exe</literal>
assembly. It makes heavy use of classes and interfaces definde in
the <literal>Spring.Services.WindowsService.Common.dll</literal>
assembly. You should reference the common assembly it if you want to
follow the advice on customization contained in the following sections
</para>
<para>
The benefits of this approach, a part from those given by separating
infrastructure code and application code (a field where Spring.NET
tries hard to succeed) is that you can think about installing a new
service at client site by simply dropping a new application assembly
in a remote directory<footnote></footnote>.
</para>
</sect1>
<sect1>
<title>The <literal>Spring.Services.WindowsService.Process.exe</literal> application</title>
<sect2>
<title>Installing</title>
<para>
The installation can be done in two ways, using the .NET SDK
<literal>installutil.exe</literal> tool or using the more mundane
<literal>Spring.Services.WindowsService.Installer.exe</literal>;
while the former is the standard, the latter is probably
more flexible. It allows you to customize the name/display name of the
service and has the ability to install multiple times the same assembly
with different names. This can be useful in a
number of scenarios, especially where you don't like, for some
reasons, to run several different logical services under the
same physical windows service.
</para>
<para><emphasis>
Be aware of the fact that the service will be installed as
running with the system account (installing with a specific
user account seems a bit buggy on Windows XP)
</emphasis></para>
<para>
That said, while <literal>installutil</literal>
<ulink url="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cptools/html/cpconinstallerutilityinstallutilexe.asp">
<citetitle>is documented on its own </citetitle></ulink>,
the command line for
<literal>Spring.Services.WindowsService.Installer.exe</literal>
is as follow:
<programlisting format='linespecific'>Spring.Services.WindowsService.Installer.exe
usage:
install service-exe-path service-display-name service-name
uninstall service-name [i|u] service-exe-path service-display-name service-name</programlisting>
for example, to install, you can invoke it with the following:
<programlisting format='linespecific'>... install Spring.Services.WindowsService.Process.exe "Spring.Service Support" spring-service</programlisting>
and to uninstall it:
<programlisting format='linespecific'>... uninstall spring-service</programlisting>
</para>
</sect2>
<sect2>
<title>Configuration</title>
<para>
The standard .NET <literal>.config</literal> file
can be used to tune some parameters of
<literal>Spring.Services.WindowsService.Process.exe</literal>,
(including log4net settings, for which it is recomended to consult
the log4net documentation).
</para>
<para>
This file also define the context run by this process; here the file in its current beauty:
<%= XmlExample("src/Spring/Spring.Services/App.config", "code") %>
</para>
<para>
As you see, the context is defined in another file: let's review the objects it defines.
</para>
<para>
Firstly, it is worth notice that in order to 'localize' the service (i.e. to know where it is installed to use that directory as
base for the deploy dir as in the above file) you should define an object like this: the name is not
very important, it is important that it is an <classname>IObjectFactoryPostProcessor</classname> and so will be
automatically applied to this application context:
<%= XmlExample("src/Spring/Spring.Services/WindowsService/Process/service-process-definition.xml", "code/localizer") %>
</para>
<para>
In that object definition you can customize the prefix for the following string
<%= CsExample("src/Spring/Spring.Services/WindowsService/Common/Localizer.cs", "code/process.format") %>
but you usually won't need it; the default value is
<%= CsExample("src/Spring/Spring.Services/WindowsService/Common/Localizer.cs", "code/localizer.def.prefix") %>
</para>
<para>
The sole important object defined by this context, i.e. the main object run by the service.
The thing you can (and should) configure is the path to the folder you will use as the deploy location;
the current definition, to avoid the need for a fully qualified path (e.g.: <literal>c:\spring\services</literal>) uses
the properties made available by the <literal>localizer</literal> above:
<%= XmlExample("src/Spring/Spring.Services/WindowsService/Process/service-process-definition.xml", "code/service") %>
</para>
<para>
The above object is then easily remoted using spring remoting utilities (please notice you should tune the remoting configuration
listed in the standard .NET <literal>.config</literal> file, listed above):
<%= XmlExample("src/Spring/Spring.Services/WindowsService/Process/service-process-definition.xml", "code/remoted.service") %>
</para>
</sect2>
</sect1>
<sect1>
<title>Running an application context as a windows service</title>
<para>
If you package an application using the layout and
conventions described here, you'll be able to run an
application context as a Windows Service.
The conventions used are modeled after those used by ASP.NET
and are very easy to follow.
</para>
<para>
As already said, you'll have a Spring.NET application context running in
a dedicated <literal>AppDomain</literal> hosted in a process running
as a windows service: that process is able to run many application contexts
simultaneously.
</para>
<para>A complete application runable as service consists of a
directory containing:
<itemizedlist spacing="compact">
<listitem>
<para>The .NET configuration file
<literal>service.config</literal>:
this file should define your application context.
Moreover this files will be used
by the CLR to configure the application domain
your application will run in, exactly as you expect.
This file has the same role of ASP.NET <literal>Web.config</literal>
file.
</para>
</listitem>
<listitem>
<para>Optional: an xml context file (<literal>watcher.xml</literal>)
defining the watcher for your application.</para>
<para>The watcher controls the automatic redeployment of the
service and is discussed more in the following section.</para>
</listitem>
<listitem>
<para>Recomended: along the lines of ASP.NET convention, a <literal>bin</literal>
subdirectory containing all
the assemblies your application needs; you can of course put
your assemblies in the same directory where you put
<literal>service.config</literal> but this is not encouraged ...
</para>
</listitem>
</itemizedlist>
</para>
<sect2>
<title><literal>service.config</literal></title>
<para>
This is the standard .NET configuration file for the
<literal>AppDomain</literal> that will host your application. It is
semantically equivalent to the ASP.NET <literal>Web.config</literal>
file.
<footnote>
<para>
<literal>log4net</literal> users please notice that (as
of 1.2 beta 9) file appenders, when dealing with a relative
file name, assume it is relative to the application
domain code base. If you use log4net, it is very handy with the mechanics used by
Spring Windows Service as every log file you will specify will
be relative the directory containing the service application.
</para>
</footnote>
</para>
<para>
This file should also define your application context. When the
service is started and stopped, the corresponding lifecycle methods
are called on all the singletons defined. Of course, singletons are
automatically instantiated by the application context when the
service starts. For more information on lifecycles in Spring.NET see
<xref linkend="objects-factory-lifecycle"/>
Here an example taken from the tests:
<%= XmlExample("test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.config", "code") %>
</para>
<para>
In this case the context is (again!) defined in another file (author's personal taste...) and the only 'service' is the
<literal>echo</literal> object (there is also a <literal>PropertyPlaceholderConfigurer</literal> just to make the example
more realistic):
<%= XmlExample("test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.xml", "code") %>
</para>
<sect3>
<title>Let the application know where it is</title>
<para>
There are some properties you may need at runtime, when your services
will run, and you cannot know in advance. Hopefully, your xml
definition file will allow to find the information it needs using some
predefined variables you can use inside the service definition file
with the standard
NAnt style <literal>${property name}</literal> syntax.</para>
<para>These properies are:
<itemizedlist spacing="compact">
<listitem>
<para><literal>spring.services.application.fullpath</literal>
that will be replaced with the full path of the application's
<literal>AppDomain.BaseDirectory</literal>, i.e., where your
application has been deployed;</para>
</listitem>
<listitem>
<para><literal>spring.services.application.name</literal> that
will be replaced with the name of the subdirectory where the
application has been deployed. Each application is deployed in
its own directory, of course;</para>
</listitem>
</itemizedlist>
</para>
<para>
These properties are accessible only if one defines a localizer in the
context like this (the localizer is a special <literal>IObjectFactoryPostProcessor</literal>:
<%= XmlExample("test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.xml", "code/localizer") %>
</para>
<para>
As you can see above, one can easily change the prefix used by that localizer and then write someting like:
<%= XmlExample("test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.xml", "code/simple") %>
</para>
</sect3>
</sect2>
<sect2>
<title><literal>watcher.xml</literal> - optional</title>
<para>
This file allows you to optionally define a watcher for your application
that can automatically redeploy it when needed.
</para>
<para>
The important thing to notice is that you can define your own
application watcher, named <literal>watcher</literal>. Here it is used
a watcher that listen for changes on the filesystem, configured to
listen for some changes and to ignore others.
</para>
<para>
You can provide your own implementation defining an object named
<literal>watcher</literal> that implements
<literal>Spring.Services.WindowsService.Common.Deploy.IApplicationWatcher</literal>:
<%= CsExample("src/Spring/Spring.Services/WindowsService/Common/Deploy/IApplicationWatcher.cs", "code/interface") %>
</para>
<para>
Please notice that this interface is currently a movable target and
will probably change before the first official release (this will probably
affect also the way a watcher will know about the application it should
monitor, as shown in a few lines).
</para>
<para>A tipical example of this file is give here:
<%= XmlExample("test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/watcher.xml", "code") %>
</para>
<para>
As you can see, if you need it, you can reference the
<literal>Spring.Services.WindowsService.Common.IApplication</literal>
object that your watcher should watch using the name
<literal>.injected.application</literal>.</para>
</sect2>
<sect2>
<title><literal>bin</literal> directory - optional</title>
<para>
This is, by default, the folder where your assemblies are placed
in the same way they are in an ASP.NET application.
</para>
<para>
Putting assemblies there is more a convention and maybe a good
practice (they are isolated from other artifacts, but maybe you will
prefer to use another directory (modify the
<literal>service.config</literal> file accordingly) or the application
directory directly (= <literal>bin</literal> parent).
</para>
<para>
Be aware of the fact that the process in which your application will
run will have its own PATH environmental variable. As such
don't expect to be successfull using dlls imported
with [DllImport] if they are not in the system PATH of the
hosting machine: while it is well known that the CLR fusion
algorithm will not consider the PATH variable, you may be biten
by assemblies using non-system dlls (SQLite and Firebird ADO.NET
providers are good examples).
</para>
<para>Reiterating, one can put assemblies in another directory
under the application directory tree, and write
the .NET configuration file (<literal>service.config</literal>)
accordingly: .NET probing algorithm is always in place.
</para>
<para>
Please notice that it is not required that
your application uses or include any of the Spring.NET assemblies:
any object in any assembly, given it has lifecycle methods, can
be run as a service: non invasive infrastructure support courtesy
of Spring.NET!
</para>
</sect2>
</sect1>
<sect1>
<title>Customizing or extending</title>
<para>
It should be said that support for windows service has been initially
developed with a clear but limited set of 'extension points' in mind,
mainly related to the way you can deploy your services:
deploy location (filesystem, zip archives, mailbox, urls, ...),
(auto-)updating features, and so on.
</para>
<para>
To better understand the following discussion, the following figure
depicts some of the inner details of
<literal>Spring.Services.WindowsService.Process.exe</literal>
at run-time:
<mediaobject>
<imageobject>
<imagedata align="center"
fileref="images/spring.windows-service.png" format="png"/>
</imageobject>
<textobject>
<phrase>Spring.Services.WindowsService.Process.exe run-time details</phrase>
</textobject>
</mediaobject>
</para>
<sect2>
<title>The <literal>.config</literal> file</title>
</sect2>
<para>
The executable <literal>Spring.Services.WindowsService.Process.exe</literal>
is somewhat configured by the corresponding
<literal>.config</literal> file.
Please notice that this file is the most important extension point
for windows service support, and it will probably be made more powerful
and flexible in the future.
</para>
<para>
For applications deployed in the standard way (i.e. on the filesystem
as explained above) the updating features are configured by the
<literal>watcher.xml</literal> file, <emphasis>if present</emphasis>,
as already seen.
</para>
<para>
There should be however, other ways to deploy your applications,
maybe just as zip files dropped somewhere on the web or sent via
e-mail.
</para>
<para>
For these scenarios, your deploy location will be something that
implements
<literal>Spring.Services.WindowsService.Common.Deploy.IDeployLocation</literal>.
<para>
Please notice that, while questionable, it actually entends
<literal>IDisposable</literal> <footnote><para>this has been done
as it is possible that a deploy location holds resources that should be
released, for example network connections, lock files or the like</para></footnote>:
</para>
<%= CsExample("src/Spring/Spring.Services/WindowsService/Common/Deploy/IDeployLocation.cs", "code/interface") %>
<%= CsExample("src/Spring/Spring.Services/WindowsService/Common/Deploy/IDeployEventSource.cs", "code/interface") %>
</para>
</sect1>
</chapter>

View File

@@ -917,7 +917,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
<programlisting>&lt;objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.net/schema/tx"
xmlns:tx="http://www.springframework.net/tx"
xmlns:db="http://www.springframework.net/database"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/schema/objects/spring-objects.xsd
http://www.springframework.net/schema/tx http://www.springframework.net/schema/tx/spring-tx-1.1.xsd"

View File

@@ -172,472 +172,4 @@ usage:
base for the deploy dir as in the above file) you should define an object like this: the name is not
very important, it is important that it is an <classname>IObjectFactoryPostProcessor</classname> and so will be
automatically applied to this application context:
<programlisting format='linespecific'>
&lt;!-- provides access to the ${spring.services.process.base.dir} property --&gt;
&lt;object
name=&quot;localizer&quot;
type=&quot;Spring.Services.WindowsService.Common.Localizer+ForProcess, Spring.Services.WindowsService.Common&quot;&gt;
&lt;!-- change this to access the property with another prefix, for example ${foo.process.base.dir}
&lt;property name=&quot;prefix&quot; value=&quot;foo&quot;/&gt;
--&gt;
&lt;/object&gt;</programlisting>
</para>
<para>
In that object definition you can customize the prefix for the following string
<programlisting format='linespecific'>
public static readonly string SpringServicesProcessBaseDirFormat = &quot;{0}.process.base.dir&quot;;</programlisting>
but you usually won't need it; the default value is
<programlisting format='linespecific'>
public static readonly string DefaultPrefix = &quot;spring.services&quot;;</programlisting>
</para>
<para>
The sole important object defined by this context, i.e. the main object run by the service.
The thing you can (and should) configure is the path to the folder you will use as the deploy location;
the current definition, to avoid the need for a fully qualified path (e.g.: <literal>c:\spring\services</literal>) uses
the properties made available by the <literal>localizer</literal> above:
<programlisting format='linespecific'>
&lt;object
name=&quot;service&quot;
type=&quot;Spring.Services.WindowsService.Common.DefaultService, Spring.Services.WindowsService.Common&quot;
init-method=&quot;Start&quot;
destroy-method=&quot;Stop&quot;&gt;
&lt;property name=&quot;DeployPath&quot; value=&quot;${spring.services.process.base.dir}/deploy&quot;/&gt;
&lt;/object&gt;</programlisting>
</para>
<para>
The above object is then easily remoted using spring remoting utilities (please notice you should tune the remoting configuration
listed in the standard .NET <literal>.config</literal> file, listed above):
<programlisting format='linespecific'>
&lt;object name=&quot;remoted.service&quot; type=&quot;Spring.Remoting.SaoExporter, Spring.Services&quot;&gt;
&lt;property name=&quot;TargetName&quot; value=&quot;service&quot;/&gt;
&lt;property name=&quot;ServiceName&quot; value=&quot;SpringWindowsService.rem&quot;/&gt;
&lt;/object&gt;</programlisting>
</para>
</sect2>
</sect1>
<sect1>
<title>Running an application context as a windows service</title>
<para>
If you package an application using the layout and
conventions described here, you'll be able to run an
application context as a Windows Service.
The conventions used are modeled after those used by ASP.NET
and are very easy to follow.
</para>
<para>
As already said, you'll have a Spring.NET application context running in
a dedicated <literal>AppDomain</literal> hosted in a process running
as a windows service: that process is able to run many application contexts
simultaneously.
</para>
<para>A complete application runable as service consists of a
directory containing:
<itemizedlist spacing="compact">
<listitem>
<para>The .NET configuration file
<literal>service.config</literal>:
this file should define your application context.
Moreover this files will be used
by the CLR to configure the application domain
your application will run in, exactly as you expect.
This file has the same role of ASP.NET <literal>Web.config</literal>
file.
</para>
</listitem>
<listitem>
<para>Optional: an xml context file (<literal>watcher.xml</literal>)
defining the watcher for your application.</para>
<para>The watcher controls the automatic redeployment of the
service and is discussed more in the following section.</para>
</listitem>
<listitem>
<para>Recomended: along the lines of ASP.NET convention, a <literal>bin</literal>
subdirectory containing all
the assemblies your application needs; you can of course put
your assemblies in the same directory where you put
<literal>service.config</literal> but this is not encouraged ...
</para>
</listitem>
</itemizedlist>
</para>
<sect2>
<title><literal>service.config</literal></title>
<para>
This is the standard .NET configuration file for the
<literal>AppDomain</literal> that will host your application. It is
semantically equivalent to the ASP.NET <literal>Web.config</literal>
file.
<footnote>
<para>
<literal>log4net</literal> users please notice that (as
of 1.2 beta 9) file appenders, when dealing with a relative
file name, assume it is relative to the application
domain code base. If you use log4net, it is very handy with the mechanics used by
Spring Windows Service as every log file you will specify will
be relative the directory containing the service application.
</para>
</footnote>
</para>
<para>
This file should also define your application context. When the
service is started and stopped, the corresponding lifecycle methods
are called on all the singletons defined. Of course, singletons are
automatically instantiated by the application context when the
service starts. For more information on lifecycles in Spring.NET see
<xref linkend="objects-factory-lifecycle"/>
Here an example taken from the tests:
<programlisting format='linespecific'>
&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name=&quot;spring&quot;&gt;
&lt;section name=&quot;context&quot; type=&quot;Spring.Context.Support.ContextHandler, Spring.Core&quot; /&gt;
&lt;section name=&quot;objects&quot; type=&quot;Spring.Context.Support.DefaultSectionHandler, Spring.Core&quot; /&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;appSettings&gt;
&lt;add key=&quot;port&quot; value=&quot;10&quot;/&gt;
&lt;/appSettings&gt;
&lt;spring&gt;
&lt;context type=&quot;Spring.Context.Support.XmlApplicationContext, Spring.Core&quot;&gt;
&lt;resource uri=&quot;file://~/service.xml&quot; /&gt;
&lt;/context&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</para>
<para>
In this case the context is (again!) defined in another file (author's personal taste...) and the only 'service' is the
<literal>echo</literal> object (there is also a <literal>PropertyPlaceholderConfigurer</literal> just to make the example
more realistic):
<programlisting format='linespecific'>
&lt;objects xmlns=&quot;http://www.springframework.net&quot;
xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd&quot;&gt;
&lt;object name=&quot;echo&quot;
type=&quot;Spring.Services.WindowsService.Samples.Echo, Spring.Services.WindowsService.Tests&quot;
init-method=&quot;Start&quot; destroy-method=&quot;Stop&quot;&gt;
&lt;property name=&quot;port&quot;&gt;&lt;value&gt;${port}&lt;/value&gt;&lt;/property&gt;
&lt;/object&gt;
&lt;object id=&quot;configurer&quot; type=&quot;Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core&quot;&gt;
&lt;property name=&quot;locations&quot;&gt;
&lt;list&gt;
&lt;value&gt;file://~/service.config&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name=&quot;configSections&quot;&gt;
&lt;list&gt;
&lt;value&gt;appSettings&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/object&gt;
&lt;/objects&gt;</programlisting>
</para>
<sect3>
<title>Let the application know where it is</title>
<para>
There are some properties you may need at runtime, when your services
will run, and you cannot know in advance. Hopefully, your xml
definition file will allow to find the information it needs using some
predefined variables you can use inside the service definition file
with the standard
NAnt style <literal>${property name}</literal> syntax.</para>
<para>These properies are:
<itemizedlist spacing="compact">
<listitem>
<para><literal>spring.services.application.fullpath</literal>
that will be replaced with the full path of the application's
<literal>AppDomain.BaseDirectory</literal>, i.e., where your
application has been deployed;</para>
</listitem>
<listitem>
<para><literal>spring.services.application.name</literal> that
will be replaced with the name of the subdirectory where the
application has been deployed. Each application is deployed in
its own directory, of course;</para>
</listitem>
</itemizedlist>
</para>
<para>
These properties are accessible only if one defines a localizer in the
context like this (the localizer is a special <literal>IObjectFactoryPostProcessor</literal>:
<programlisting format='linespecific'>
&lt;!-- provides access to the ${spring.services.application.*} properties --&gt;
&lt;object
name=&quot;localizer&quot;
type=&quot;Spring.Services.WindowsService.Common.Localizer+ForApplication, Spring.Services.WindowsService.Common&quot;&gt;
&lt;!-- change this to access the property with another prefix, for example ${foo.application.base.dir}
--&gt;
&lt;property name=&quot;prefix&quot; value=&quot;myPrefix&quot;/&gt;
&lt;/object&gt;</programlisting>
</para>
<para>
As you can see above, one can easily change the prefix used by that localizer and then write someting like:
<programlisting format='linespecific'>
&lt;object name=&quot;simple&quot;
type=&quot;Spring.Services.WindowsService.Samples.Simple, Spring.Services.WindowsService.Tests&quot;
init-method=&quot;Start&quot; destroy-method=&quot;Stop&quot;&gt;
&lt;constructor-arg index=&quot;0&quot; value=&quot;${myPrefix.application.name},${myPrefix.application.fullPath}&quot;/&gt;
&lt;property name=&quot;AppName&quot;&gt;
&lt;value&gt;${myPrefix.application.name}&lt;/value&gt;
&lt;/property&gt;
&lt;property name=&quot;AppFullPath&quot;&gt;
&lt;value&gt;${myPrefix.application.fullpath}&lt;/value&gt;
&lt;/property&gt;
&lt;/object&gt;</programlisting>
</para>
</sect3>
</sect2>
<sect2>
<title><literal>watcher.xml</literal> - optional</title>
<para>
This file allows you to optionally define a watcher for your application
that can automatically redeploy it when needed.
</para>
<para>
The important thing to notice is that you can define your own
application watcher, named <literal>watcher</literal>. Here it is used
a watcher that listen for changes on the filesystem, configured to
listen for some changes and to ignore others.
</para>
<para>
You can provide your own implementation defining an object named
<literal>watcher</literal> that implements
<literal>Spring.Services.WindowsService.Common.Deploy.IApplicationWatcher</literal>:
<programlisting format='linespecific'>
/// &lt;summary&gt;
Interface defining the contract for an application watcher.
&lt;p&gt;An application watcher is responsible to dispatch an
&lt;see cref=&quot;IApplicationWatcherFactory&quot;&gt;event&lt;/see&gt; whenever it thinks the
application has been updated.&lt;/p&gt;
&lt;p&gt;Usually it should not raise other kind of events
as they are usually raised by the &lt;see cref=&quot;FileSystemApplicationWatcher&quot;/&gt;
that creates the watcher itself&lt;/p&gt;
&lt;/summary&gt;
&lt;remarks&gt;Usually instances of this interface need to be disposed&lt;/remarks&gt;
&lt;seealso cref=&quot;DeployEventArgs&quot;/&gt;
&lt;seealso cref=&quot;IDeployLocation&quot;/&gt;
&lt;seealso cref=&quot;DeployEventType.ApplicationUpdated&quot;/&gt;
&lt;seealso cref=&quot;DeployEventAggregator&quot;/&gt;
&lt;seealso cref=&quot;IDeployLocation&quot;/&gt;
&lt;seealso cref=&quot;DeployEventType&quot;/&gt;
public interface IApplicationWatcher : IDisposable
{
/// &lt;summary&gt;
/// The watched application
/// &lt;/summary&gt;
IApplication Application {get; }
/// &lt;summary&gt;
/// Start to watch the application, using the given dispatcher to
/// dispatch deply events
/// &lt;/summary&gt;
/// &lt;param name=&quot;dispatcher&quot;&gt;the dispatcher used to raise deploy events&lt;/param&gt;
void StartWatching (IDeployEventDispatcher dispatcher);
/// &lt;summary&gt;
/// Stop to watch the application.
/// &lt;/summary&gt;
void StopWatching ();
/// &lt;summary&gt;
/// If physical events watched by this watcher should be filtered, this methods
/// will allow to set filters that allows and disallows the event to be raised
/// by the watcher.
/// &lt;/summary&gt;
/// &lt;param name=&quot;allows&quot;&gt;the list of allowing filters&lt;/param&gt;
/// &lt;param name=&quot;disallows&quot;&gt;the list of disallowing filters&lt;/param&gt;
/// &lt;seealso cref=&quot;FilteringSupport&quot;/&gt;
/// &lt;seealso cref=&quot;RegularExpressionFilter&quot;/&gt;
void SetFilters (IList allows, IList disallows);
}</programlisting>
</para>
<para>
Please notice that this interface is currently a movable target and
will probably change before the first official release (this will probably
affect also the way a watcher will know about the application it should
monitor, as shown in a few lines).
</para>
<para>A tipical example of this file is give here:
<programlisting format='linespecific'>
&lt;objects&gt;
&lt;object name='watcher'
type='Spring.Services.WindowsService.Common.Deploy.FileSystem.FileSystemApplicationWatcher'&gt;
&lt;!--
we can get access to the IApplication we are asked to monitor
using a reference like the following
--&gt;
&lt;constructor-arg ref='.injected.application'/&gt;
&lt;!-- sometimes the windows OS will decide to not give you the same case you see in explorer:
in fact one should consider this OS case-insensitive with regard to file names ...
The following property, true by default can however be tuned
&lt;property name=&quot;ignoreCase&quot; value=&quot;false&quot;/&gt;
--&gt;
&lt;property name=&quot;includes&quot;&gt;
&lt;list&gt;
&lt;value&gt;wwwroot/bin/*.*&lt;/value&gt;
&lt;value&gt;service.config&lt;/value&gt;
&lt;value&gt;service.xml&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;!--
&lt;property name=&quot;excludes&quot;&gt;
&lt;list&gt;
&lt;value&gt;Db/**/*.*&lt;/value&gt;
&lt;value&gt;Jobs&lt;/value&gt;
&lt;value&gt;Jobs&lt;/value&gt;
&lt;value&gt;**/*.log&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
--&gt;
&lt;/object&gt;
&lt;/objects&gt;</programlisting>
</para>
<para>
As you can see, if you need it, you can reference the
<literal>Spring.Services.WindowsService.Common.IApplication</literal>
object that your watcher should watch using the name
<literal>.injected.application</literal>.</para>
</sect2>
<sect2>
<title><literal>bin</literal> directory - optional</title>
<para>
This is, by default, the folder where your assemblies are placed
in the same way they are in an ASP.NET application.
</para>
<para>
Putting assemblies there is more a convention and maybe a good
practice (they are isolated from other artifacts, but maybe you will
prefer to use another directory (modify the
<literal>service.config</literal> file accordingly) or the application
directory directly (= <literal>bin</literal> parent).
</para>
<para>
Be aware of the fact that the process in which your application will
run will have its own PATH environmental variable. As such
don't expect to be successfull using dlls imported
with [DllImport] if they are not in the system PATH of the
hosting machine: while it is well known that the CLR fusion
algorithm will not consider the PATH variable, you may be biten
by assemblies using non-system dlls (SQLite and Firebird ADO.NET
providers are good examples).
</para>
<para>Reiterating, one can put assemblies in another directory
under the application directory tree, and write
the .NET configuration file (<literal>service.config</literal>)
accordingly: .NET probing algorithm is always in place.
</para>
<para>
Please notice that it is not required that
your application uses or include any of the Spring.NET assemblies:
any object in any assembly, given it has lifecycle methods, can
be run as a service: non invasive infrastructure support courtesy
of Spring.NET!
</para>
</sect2>
</sect1>
<sect1>
<title>Customizing or extending</title>
<para>
It should be said that support for windows service has been initially
developed with a clear but limited set of 'extension points' in mind,
mainly related to the way you can deploy your services:
deploy location (filesystem, zip archives, mailbox, urls, ...),
(auto-)updating features, and so on.
</para>
<para>
To better understand the following discussion, the following figure
depicts some of the inner details of
<literal>Spring.Services.WindowsService.Process.exe</literal>
at run-time:
<mediaobject>
<imageobject>
<imagedata align="center"
fileref="images/spring.windows-service.png" format="png"/>
</imageobject>
<textobject>
<phrase>Spring.Services.WindowsService.Process.exe run-time details</phrase>
</textobject>
</mediaobject>
</para>
<sect2>
<title>The <literal>.config</literal> file</title>
</sect2>
<para>
The executable <literal>Spring.Services.WindowsService.Process.exe</literal>
is somewhat configured by the corresponding
<literal>.config</literal> file.
Please notice that this file is the most important extension point
for windows service support, and it will probably be made more powerful
and flexible in the future.
</para>
<para>
For applications deployed in the standard way (i.e. on the filesystem
as explained above) the updating features are configured by the
<literal>watcher.xml</literal> file, <emphasis>if present</emphasis>,
as already seen.
</para>
<para>
There should be however, other ways to deploy your applications,
maybe just as zip files dropped somewhere on the web or sent via
e-mail.
</para>
<para>
For these scenarios, your deploy location will be something that
implements
<literal>Spring.Services.WindowsService.Common.Deploy.IDeployLocation</literal>.
<para>
Please notice that, while questionable, it actually entends
<literal>IDisposable</literal> <footnote><para>this has been done
as it is possible that a deploy location holds resources that should be
released, for example network connections, lock files or the like</para></footnote>:
</para>
<programlisting format='linespecific'>
/// &lt;summary&gt;
/// Interface defining how a deploy location should look like
/// &lt;/summary&gt;
public interface IDeployLocation : IDeployEventSource, IDisposable
{
/// &lt;summary&gt;
/// The list of applications deployed at this location
/// Usually non-valid applications are not listed
/// &lt;/summary&gt;
/// &lt;seealso cref=&quot;Application&quot;/&gt;
IList Applications { get; }
}</programlisting>
<programlisting format='linespecific'>
/// &lt;summary&gt;
/// Interface defining the contract for an object acting as the source of
/// deploy events (application added, removed, updated)
/// &lt;/summary&gt;
/// &lt;seealso cref=&quot;DeployEventArgs&quot;/&gt;
/// &lt;seealso cref=&quot;DeployEventHandler&quot;/&gt;
public interface IDeployEventSource
{
/// &lt;summary&gt;
/// The multicaster for deploy events
/// &lt;/summary&gt;
event DeployEventHandler DeployEvent;
}</programlisting>
</para>
</sect1>
</chapter>

View File

@@ -8,7 +8,7 @@
<para>This appendix details the use of XML Schema-based configuration in
Spring.</para>
<para> The <emphasis>'classic' </emphasis>
<para>The <emphasis>'classic' </emphasis>
<literal>&lt;object/&gt;</literal>-based schema is good, but its
generic-nature comes with a price in terms of configuration overhead.
Creating a custom XML Schema-based configuration makes Spring XML
@@ -58,7 +58,7 @@
you can copy and paste (!) and then plug
<literal>&lt;object/&gt;</literal> definitions into like you have always
done. However, the entire point of using custom schema tags is to make
configuration easier. </para>
configuration easier.</para>
</section>
<para>The rest of this chapter gives an overview of custom XML Schema
@@ -90,10 +90,14 @@
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;object xmlns="http://www.springframework.net"
xmlns:aop="http://www.springframework.org/schema/aop"
<emphasis role="bold"> xmlns:tx="http://www.springframework.org/schema/tx"</emphasis>&gt;
xmlns:aop="http://www.springframework.net/aop"
<emphasis role="bold"> xmlns:tx="http://www.springframework.net/tx"</emphasis>&gt;
<lineannotation>&lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
<lineannotation> &lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
&lt;!-- &lt;tx/&gt; transaction definitions here --&gt;
&lt;!-- &lt;aop/&gt; AOP definitions here --&gt;
&lt;/object&gt;</programlisting>
@@ -106,6 +110,28 @@
the tags in the <literal>aop</literal> namespace are available to
you.</para>
</note>
<para>You will also need to configure the AOP and Transaction namespace
parsers in the main .NET application configuration file as shown
below</para>
<programlisting>&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity --&gt;
&lt;section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" /&gt;
&lt;parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data" /&gt;
&lt;/parsers&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</section>
<section id="xsd-config-body-schemas-aop">
@@ -123,12 +149,33 @@
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<emphasis role="bold">xmlns:aop="http://www.springframework.org/schema/aop"</emphasis>&gt;
<emphasis role="bold">xmlns:aop="http://www.springframework.net/aop"</emphasis>&gt;
<lineannotation>&lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
<lineannotation> &lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
&lt;!-- &lt;aop/&gt; AOP definitions here --&gt;
&lt;/objects&gt;</programlisting>
<para>You will also need to configure the AOP namespace parser in the
main .NET application configuration file as shown below</para>
<programlisting>&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity --&gt;
&lt;section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" /&gt;
&lt;/parsers&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</section>
<section id="xsd-config-body-schemas-db">
@@ -143,12 +190,33 @@
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<emphasis role="bold">xmlns:db="http://www.springframework.org/schema/db"</emphasis>&gt;
<emphasis role="bold">xmlns:db="http://www.springframework.net/db"</emphasis>&gt;
<lineannotation>&lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
<lineannotation> &lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
&lt;!-- &lt;db/&gt; database definitions here --&gt;
&lt;/objects&gt;</programlisting>
<para>You will also need to configure the Database namespace parser in
the main .NET application configuration file as shown below</para>
<programlisting>&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity --&gt;
&lt;section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" /&gt;
&lt;/parsers&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</section>
<section id="xsd-config-body-schemas-remoting">
@@ -160,13 +228,34 @@
the chapter <xref linkend="remoting" /></para>
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;objects xmlns="http://www.springframework.org/schema/objects"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<emphasis role="bold">xmlns:r="http://www.springframework.org/schema/remoting"</emphasis>&gt;
&lt;objects xmlns="http://www.springframework.net"
<emphasis role="bold">xmlns:r="http://www.springframework.net/remoting"</emphasis>&gt;
<lineannotation>&lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
<lineannotation> &lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
&lt;!-- &lt;r/&gt; remoting definitions here --&gt;
&lt;/objects&gt;</programlisting>
<para>You will also need to configure the remoting namespace parser in
the main .NET application configuration file as shown below</para>
<programlisting>&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity --&gt;
&lt;section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Remoting.Config.RemotingNamespaceParser, Spring.Services" /&gt;
&lt;/parsers&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</section>
<section id="xsd-config-body-schemas-validation">
@@ -178,13 +267,34 @@
linkend="validation" /></para>
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<emphasis role="bold">xmlns:v="http://www.springframework.org/schema/validation"</emphasis>&gt;
&lt;objects xmlns="http://www.springframework.net"
<emphasis role="bold">xmlns:v="http://www.springframework.net/validation"</emphasis>&gt;
<lineannotation>&lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
<lineannotation> &lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
&lt;!-- &lt;v/&gt; valdiation definitions here --&gt;
&lt;/objects&gt;</programlisting>
<para>You will also need to configure the validation namespace parser in
the main .NET application configuration file as shown below</para>
<programlisting>&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity --&gt;
&lt;section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Validation.Config.ValidationNamespaceParser, Spring.Core" /&gt;
&lt;/parsers&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</section>
<section id="xsd-config-body-schemas-objects">

View File

@@ -0,0 +1,140 @@
////<examples>
using System;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using Spring.Threading;
namespace Spring.Examples.Pool
{
public class Grep : IRunnable
{
private string file;
private string regexPattern;
public class Match
{
string fileName, line;
int lineNum;
public Match(string fileName, int lineNum, string line)
{
this.fileName = fileName;
this.lineNum = lineNum;
this.line = line;
}
public void Print()
{
Console.Out.WriteLine("thread #{0}: {1}: {2}: {3}", Thread.CurrentThread.GetHashCode(), fileName, lineNum, line);
}
}
public class Error
{
string file;
Exception e;
public Error(string file, Exception e)
{
this.file = file;
this.e = e;
}
public void Print()
{
Console.Out.WriteLine("file [{0}]: {1}", file, e.Message);
}
}
public Grep(string file, string regexPattern)
{
this.file = file;
this.regexPattern = regexPattern;
}
public void Run()
{
try
{
int lineNum = 1;
using (TextReader r = File.OpenText(file))
{
string line = null;
while ((line = r.ReadLine()) != null)
{
if (Regex.IsMatch(line, Regex.Escape(regexPattern), RegexOptions.Singleline))
{
new Grep.Match(file, lineNum, line).Print();
}
lineNum++;
}
}
}
catch (Exception e)
{
new Grep.Error(file, e).Print();
}
}
}
public class ParallelGrep
{
//// <example name="parallel-grep-class">
private PooledQueuedExecutor executor;
public ParallelGrep(int size)
{
executor = new PooledQueuedExecutor(size);
}
public void Recurse(string startPath, string filePattern, string regexPattern)
{
foreach (string file in Directory.GetFiles(startPath, filePattern))
{
executor.Execute(new Grep(file, regexPattern));
}
foreach (string directory in Directory.GetDirectories(startPath))
{
Recurse(directory, filePattern, regexPattern);
}
}
public void Stop()
{
executor.Stop();
}
//// </example>
//// <example name="parallel-grep-main">
public static void Main(string[] args)
{
if (args.Length < 3)
{
Console.Out.WriteLine("usage: {0} regex directory file-pattern [pool-size]", Assembly.GetEntryAssembly().CodeBase);
Environment.Exit(1);
}
string regexPattern = args[0];
string startPath = args[1];
string filePattern = args[2];
int size = 10;
try
{
size = Int32.Parse(args[3]);
}
catch
{
}
Console.Out.WriteLine ("pool size {0}", size);
ParallelGrep grep = new ParallelGrep(size);
grep.Recurse(startPath, filePattern, regexPattern);
grep.Stop();
}
//// </example>
}
}
//// </examples>

View File

@@ -0,0 +1,190 @@
////<examples>
using System;
using System.Collections;
using System.Threading;
using Spring.Pool;
using Spring.Threading;
namespace Spring.Examples.Pool
{
/// <summary>
/// Factory of <see cref="QueuedExecutor"/> istances.
/// </summary>
//// <example name='factory-declaration'>
public class QueuedExecutorPoolableFactory : IPoolableObjectFactory
{
//// </example>
//// <example name='destroy'>
void IPoolableObjectFactory.DestroyObject(object o)
{
// ah, self documenting code:
// Here you can see that we decided to let the
// executor process all the currently queued tasks.
QueuedExecutor executor = o as QueuedExecutor;
executor.ShutdownAfterProcessingCurrentlyQueuedTasks();
}
//// </example>
//// <example name="validate">
bool IPoolableObjectFactory.ValidateObject(object o)
{
QueuedExecutor executor = o as QueuedExecutor;
return executor.Thread != null;
}
//// </example>
//// <example name='activate'>
void IPoolableObjectFactory.ActivateObject(object o)
{
QueuedExecutor executor = o as QueuedExecutor;
executor.Restart();
}
//// </example>
//// <example name='passivate'>
void IPoolableObjectFactory.PassivateObject(object o)
{
}
//// </example>
//// <example name='make'>
object IPoolableObjectFactory.MakeObject()
{
// to actually make this work as a pooled executor
// use a bounded queue of capacity 1.
// If we don't do this one of the queued executors
// will accept all the queued IRunnables as, by default
// its queue is unbounded, and the PooledExecutor
// will happen to always run only one thread ...
return new QueuedExecutor(new BoundedBuffer(1));
}
//// </example>
}
//// <example name="holder">
public class PooledObjectHolder : IDisposable
{
IObjectPool pool;
object pooled;
/// <summary>
/// Builds a new <see cref="PooledObjectHolder"/>
/// trying to borrow an object form it
/// </summary>
/// <param name="pool"></param>
private PooledObjectHolder(IObjectPool pool)
{
this.pool = pool;
this.pooled = pool.BorrowObject();
}
/// <summary>
/// Allow to access the borrowed pooled object
/// </summary>
public object Pooled
{
get
{
return pooled;
}
}
/// <summary>
/// Returns the borrowed object to the pool
/// </summary>
public void Dispose()
{
pool.ReturnObject(pooled);
}
/// <summary>
/// Creates a new <see cref="PooledObjectHolder"/> for the
/// given pool.
/// </summary>
public static PooledObjectHolder UseFrom(IObjectPool pool)
{
return new PooledObjectHolder(pool);
}
}
//// </example>
public class PooledQueuedExecutor : IExecutor
{
Spring.Pool.SimplePool pool;
private IList syncs;
class Queuer
{
IObjectPool pool;
IRunnable runnable;
private ISync sync;
public Queuer (IObjectPool pool, IRunnable runnable)
{
this.pool = pool;
this.runnable = runnable;
this.sync = new Latch();
}
public void Queue ()
{
//// <example name="execute">
using (PooledObjectHolder holder = PooledObjectHolder.UseFrom(pool))
{
QueuedExecutor executor = (QueuedExecutor) holder.Pooled;
executor.Execute(runnable);
}
//// </example>
sync.Release();
}
public static ISync Queue (IObjectPool pool, IRunnable runnable)
{
Queuer queuer = new Queuer(pool, runnable);
Thread thread = new Thread(new ThreadStart(queuer.Queue));
thread.Start();
return queuer.Sync;
}
public ISync Sync
{
get
{
return sync;
}
}
}
public PooledQueuedExecutor(int size)
{
//// <example name="create-pool">
pool = new SimplePool(new QueuedExecutorPoolableFactory(), size);
//// </example>
syncs = ArrayList.Synchronized(new ArrayList());
}
public PooledQueuedExecutor()
: this(10)
{
}
public void Execute(IRunnable runnable)
{
// queue the task and remember its ISync ...
syncs.Add(Queuer.Queue(pool, runnable));
}
//// <example name="stop">
public void Stop ()
{
// waits for all the grep-task to have been queued ...
foreach (ISync sync in syncs)
{
sync.Acquire();
}
pool.Close();
}
//// </example>
}
}
//// </examples>

View File

@@ -0,0 +1,120 @@
<VisualStudioProject>
<CSHARP
ProjectType = "Local"
ProductVersion = "7.10.3077"
SchemaVersion = "2.0"
ProjectGuid = "{C261D9ED-85C3-4B35-BE48-7156F5B17430}"
>
<Build>
<Settings
ApplicationIcon = ""
AssemblyKeyContainerName = ""
AssemblyName = "Spring.Examples.Pool"
AssemblyOriginatorKeyFile = ""
DefaultClientScript = "JScript"
DefaultHTMLPageLayout = "Grid"
DefaultTargetSchema = "IE50"
DelaySign = "false"
OutputType = "Exe"
PreBuildEvent = ""
PostBuildEvent = ""
RootNamespace = "Spring"
RunPostBuildEvent = "OnOutputUpdated"
StartupObject = ""
>
<Config
Name = "Debug"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "DEBUG;TRACE"
DocumentationFile = ""
DebugSymbols = "true"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "false"
OutputPath = "bin\Debug\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
<Config
Name = "Release"
AllowUnsafeBlocks = "false"
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "TRACE"
DocumentationFile = ""
DebugSymbols = "false"
FileAlignment = "4096"
IncrementalBuild = "false"
NoStdLib = "false"
NoWarn = ""
Optimize = "true"
OutputPath = "bin\Release\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "4"
/>
</Settings>
<References>
<Reference
Name = "System"
AssemblyName = "System"
HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.dll"
/>
<Reference
Name = "System.Data"
AssemblyName = "System.Data"
HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Data.dll"
/>
<Reference
Name = "System.XML"
AssemblyName = "System.Xml"
HintPath = "..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"
/>
<Reference
Name = "log4net"
AssemblyName = "log4net"
HintPath = "..\..\..\lib\Net\1.1\log4net.dll"
/>
<Reference
Name = "System.Web"
AssemblyName = "System.Web"
HintPath = "..\..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Web.dll"
/>
<Reference
Name = "System.Web.Services"
AssemblyName = "System.Web.Services"
HintPath = "..\..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Web.Services.dll"
/>
<Reference
Name = "Spring.Core"
Project = "{710961A3-0DF4-49E4-A26E-F5B9C044AC84}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
/>
</References>
</Build>
<Files>
<Include>
<File
RelPath = "Examples\Pool\Grep.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Examples\Pool\PooledQueuedExecutor.cs"
SubType = "Code"
BuildAction = "Compile"
/>
</Include>
</Files>
</CSHARP>
</VisualStudioProject>

View File

@@ -0,0 +1,29 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Core", "..\..\..\src\Spring\Spring.Core\Spring.Core.2003.csproj", "{710961A3-0DF4-49E4-A26E-F5B9C044AC84}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Examples.Pool", "Spring.Examples.Pool.csproj", "{C261D9ED-85C3-4B35-BE48-7156F5B17430}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Debug.ActiveCfg = Debug|.NET
{710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Debug.Build.0 = Debug|.NET
{710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Release.ActiveCfg = Release|.NET
{710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Release.Build.0 = Release|.NET
{C261D9ED-85C3-4B35-BE48-7156F5B17430}.Debug.ActiveCfg = Debug|.NET
{C261D9ED-85C3-4B35-BE48-7156F5B17430}.Debug.Build.0 = Debug|.NET
{C261D9ED-85C3-4B35-BE48-7156F5B17430}.Release.ActiveCfg = Release|.NET
{C261D9ED-85C3-4B35-BE48-7156F5B17430}.Release.Build.0 = Release|.NET
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

Binary file not shown.

Binary file not shown.

View File

@@ -79,16 +79,6 @@
AssemblyName = "System.Xml"
HintPath = "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"
/>
<Reference
Name = "Spring.Core.2003"
Project = "{710961A3-0DF4-49E4-A26E-F5B9C044AC84}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
/>
<Reference
Name = "Spring.Data.2003"
Project = "{E10A3BED-795F-41CB-A4A8-8C4B342ACDDF}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
/>
<Reference
Name = "nunit.framework"
AssemblyName = "nunit.framework"
@@ -124,6 +114,16 @@
AssemblyName = "Common.Logging"
HintPath = "..\..\..\lib\Net\1.1\Common.Logging.dll"
/>
<Reference
Name = "Spring.Core.2003"
Project = "{710961A3-0DF4-49E4-A26E-F5B9C044AC84}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
/>
<Reference
Name = "Spring.Data.2003"
Project = "{E10A3BED-795F-41CB-A4A8-8C4B342ACDDF}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
/>
<Reference
Name = "Spring.Data.NHibernate12.2003"
Project = "{2E12AE3E-5690-46A5-9F89-80F1D3004ADB}"

View File

@@ -224,11 +224,26 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Data\Objects\AbstractAdoQueryTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Data\Objects\AdoOperationTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Data\Objects\AdoQueryTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Data\Objects\StoredProcedureTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Support\ErrorCodeExceptionTranslatorTests.cs"
SubType = "Code"

View File

@@ -268,7 +268,7 @@
/>
<File
RelPath = "Util\ControlInterceptionTests.cs"
SubType = "ASPXCodeBehind"
SubType = "Code"
BuildAction = "Compile"
/>
<File