Initial import!
This commit is contained in:
BIN
doc/reference/src/templated/AgileDocs.Core.dll
Normal file
BIN
doc/reference/src/templated/AgileDocs.Core.dll
Normal file
Binary file not shown.
162
doc/reference/src/templated/misc.xml
Normal file
162
doc/reference/src/templated/misc.xml
Normal file
@@ -0,0 +1,162 @@
|
||||
<%@ CodeTemplate %>
|
||||
<%@ Import Namespace="System.IO" %>
|
||||
<%@ Assembly Name="AgileDocs.Core" %>
|
||||
<%@ Import Namespace="AgileDocs.Core" %>
|
||||
|
||||
<script runat="template">
|
||||
|
||||
string Example(string example, string what)
|
||||
{
|
||||
return "<programlisting format='linespecific' xml:space='preserve'>"
|
||||
+ XmlPeek.HtmlEncode (
|
||||
XmlPeek.ExtractAndQueryXPath(
|
||||
Path.Combine("test/Spring/Spring.Core.Tests/Data/PathMatcher", "Examples.test"),
|
||||
String.Format("examples/example[@name='{0}']/{1}", example, what),
|
||||
new ExtractXml("#", null)))
|
||||
+ "</programlisting>";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<chapter id="misc">
|
||||
<title>Spring.NET miscellanea</title>
|
||||
<sect1>
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
This chapter contains miscellanea information on features, goodies, caveats
|
||||
that does not belong to any paricular area.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>PathMatcher</title>
|
||||
<para>
|
||||
<emphasis>Note, Spring.Util.PathMatcher is
|
||||
currently only available in CVS, not the RC3 release. If you want to use these feature
|
||||
please get the code from CVS
|
||||
<ulink url="http://opensource.atlassian.com/confluence/spring/display/NET/Project+Structure">(instructions)</ulink>
|
||||
or from the download section of the
|
||||
Spring.NET website that contains an .zip with the full CVS tree.
|
||||
</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
<literal>Spring.Util.PathMatcher</literal> provides <literal>Ant/NAnt</literal>-like path name matching
|
||||
features.
|
||||
</para>
|
||||
<para>To do the match, you use the method:
|
||||
<programlisting format='linespecific' xml:space='preserve'><%=
|
||||
XmlPeek.HtmlEncode (
|
||||
XmlPeek.ExtractAndQueryXPath(
|
||||
"src/Spring/Spring.Core/Util/PathMatcher.cs",
|
||||
"fragments/fragment[@name='match-method']"))
|
||||
%></programlisting>
|
||||
</para>
|
||||
<para>If you want to decide if case is important or not use the method:
|
||||
<programlisting format='linespecific' xml:space='preserve'><%=
|
||||
XmlPeek.HtmlEncode (
|
||||
XmlPeek.ExtractAndQueryXPath(
|
||||
"src/Spring/Spring.Core/Util/PathMatcher.cs",
|
||||
"fragments/fragment[@name='match-method-nocase']"))
|
||||
%></programlisting>
|
||||
</para>
|
||||
<sect2>
|
||||
<title>General rules</title>
|
||||
<para>
|
||||
To build your pattern, you use the <literal>*</literal>, <literal>?</literal>
|
||||
and <literal>**</literal> building blocks:
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><literal>*</literal>: matches any number of non slash
|
||||
characters;
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>?</literal>: matches exactly 1 (one) non slash/dot
|
||||
character;
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>**</literal>: matches any subdirectory, without
|
||||
taking care of the depth;
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Matching filenames</title>
|
||||
<para>
|
||||
A file name can be matched using the following
|
||||
notation:
|
||||
<%= Example("filename", "pattern") %>
|
||||
matches:
|
||||
<%= Example("filename", "match") %>
|
||||
does not match:
|
||||
<%= Example("filename", "dont.match") %>
|
||||
</para>
|
||||
<para>
|
||||
The classical all files pattern:
|
||||
<%= Example("filename-all", "pattern") %>
|
||||
matches:
|
||||
<%= Example("filename-all", "match") %>
|
||||
does not match:
|
||||
<%= Example("filename-all", "dont.match") %>
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Matching subdirectories</title>
|
||||
<para>
|
||||
A directory name can be matched at any depth level using the following
|
||||
notation:
|
||||
<%= Example("subdir", "pattern") %>
|
||||
That pattern matches the following paths:
|
||||
<%= Example("subdir", "match") %>
|
||||
but does not match these:
|
||||
<%= Example("subdir", "dont.match") %>
|
||||
</para>
|
||||
<para>
|
||||
You can compose subdirectories to match like this:
|
||||
<%= Example("double-subdir", "pattern") %>
|
||||
That pattern matches the following paths:
|
||||
<%= Example("double-subdir", "match") %>
|
||||
but does not match these:
|
||||
<%= Example("double-subdir", "dont.match") %>
|
||||
</para>
|
||||
<para>
|
||||
You can use more advanced patterns:
|
||||
<%= Example("subdir-2", "pattern") %>
|
||||
matches:
|
||||
<%= Example("subdir-2", "match") %>
|
||||
does not match:
|
||||
<%= Example("subdir-2", "dont.match") %>
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Case does matter, slashes don't</title>
|
||||
<para>
|
||||
.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:
|
||||
<%= Example("case-sensitive", "pattern") %>
|
||||
matches:
|
||||
<%= Example("case-sensitive", "match") %>
|
||||
but does not match:
|
||||
<%= Example("case-sensitive", "dont.match") %>
|
||||
</para>
|
||||
<para>If you do not matter about case, you should explicitly tell the
|
||||
<literal>Pathmatcher</literal>.</para>
|
||||
<para>
|
||||
Back and forward slashes, in the very same cross-platform spirit, are
|
||||
not important:
|
||||
<%= Example("slashes", "pattern") %>
|
||||
matches all the following paths:
|
||||
<%= Example("slashes", "match") %>
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
158
doc/reference/src/templated/pooling-example.xml
Normal file
158
doc/reference/src/templated/pooling-example.xml
Normal file
@@ -0,0 +1,158 @@
|
||||
<%@ CodeTemplate %>
|
||||
<%@ Import Namespace="System.IO" %>
|
||||
<%@ Assembly Name="AgileDocs.Core" %>
|
||||
<%@ Import Namespace="AgileDocs.Core" %>
|
||||
|
||||
<script runat="template">
|
||||
|
||||
string PoolExample (string fileName, string xpath)
|
||||
{
|
||||
return "<programlisting format='linespecific' xml:space='preserve'>"
|
||||
+ XmlPeek.HtmlEncode (
|
||||
XmlPeek.ExtractAndQueryXPath(
|
||||
Path.Combine("examples/Spring/Spring.Examples.Pool/Examples/Pool", fileName),
|
||||
String.Format("examples/example[@name='{0}']", xpath)))
|
||||
+ "</programlisting>";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<sect1>
|
||||
<title>Pooling example</title>
|
||||
<para>
|
||||
The idea is to build an executor backed by a pool of
|
||||
<literal>QueuedExecutor</literal>: this will show how Spring.NET
|
||||
provides some useful low-level/high-quality reusable threading and
|
||||
pooling abstractions.
|
||||
This executor will provide parallel executions (in our case
|
||||
<literal>grep</literal>-like file scans). <emphasis>Note: This example
|
||||
is not in the 1.0.0 release to its use of classes in the Spring.Threading
|
||||
namespace scheduled for release in Spring 1.1. To access ths example
|
||||
please get the code from CVS <ulink url="http://opensource.atlassian.com/confluence/spring/display/NET/Project+Structure">(instructions)</ulink> or from the download section of the
|
||||
Spring.NET website that contains an .zip with the full CVS tree.</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
Some information on <literal>QueuedExecutor</literal> is helpful to
|
||||
better understand the implementation and to possibly disagree with it.
|
||||
Keep in mind that the point is to show how to develop your own
|
||||
object-pool.
|
||||
</para>
|
||||
<para>
|
||||
A <literal>QueuedExecutor</literal> is an executor where
|
||||
<literal>IRunnable</literal> instances are run serialy by a worker
|
||||
thread. When you <literal>Execute</literal> with a
|
||||
<literal>QueuedExecutor</literal>, your request is queued; at some
|
||||
point in the future your request will be taken and executed by the
|
||||
worker thread: in case of error the thread is terminated.
|
||||
However
|
||||
this executor recreates its worker thread as needed.
|
||||
</para>
|
||||
<para>Last but not least, this executor can be shut down in
|
||||
a few different ways (please refer to the Spring.NET SDK documentation).
|
||||
Given its simplicity, it is very powerful.
|
||||
</para>
|
||||
<para>
|
||||
The example project <literal>Spring.Examples.Pool</literal> provides
|
||||
an implementation of a pooled executor, backed by n instances of
|
||||
<literal>Spring.Threading.QueuedExecutor</literal>: please ignore
|
||||
the fact that <literal>Spring.Threading</literal> includes already a
|
||||
very different implementation of a <literal>PooledExecutor</literal>:
|
||||
here we wanto to use a pool of <literal>QueuedExecutor</literal>s.
|
||||
</para>
|
||||
<para>
|
||||
This executor will be used to implement a parallel
|
||||
recursive <literal>grep</literal>-like console executable.
|
||||
</para>
|
||||
<sect2>
|
||||
<title>Implementing <literal>Spring.Pool.IPoolableObjectFactory</literal></title>
|
||||
<para>
|
||||
In order to use the <literal>SimplePool</literal> implementation,
|
||||
the first thing to do is to implement the <literal>IPoolableObjectFactory</literal>
|
||||
interface. This interface is intended to be implemented by objects
|
||||
that can create the type of objects that should be pooled.
|
||||
The <literal>SimplePool</literal>
|
||||
will call the lifecycle methods on <literal>IPoolableObjectFactory</literal> interface
|
||||
(<literal>MakeObject, ActivateObject, ValidateObject, PassivateObject, and DestroyObject</literal>)
|
||||
as appropriate when the pool is created, objects are borrowed and returned to the pool, and when
|
||||
the pool is destroyed.
|
||||
</para>
|
||||
<para>
|
||||
In our case, as already said, we want to to implement a pool
|
||||
of <literal>QueuedExecutor</literal>. Ok, here the declaration:
|
||||
<%= PoolExample("PooledQueuedExecutor.cs", "factory-declaration") %>
|
||||
the first task a factory should do is to create objects:
|
||||
<%= PoolExample("PooledQueuedExecutor.cs", "make") %>
|
||||
and should be also able to destroy them:
|
||||
<%= PoolExample("PooledQueuedExecutor.cs", "destroy") %>
|
||||
</para>
|
||||
<para>
|
||||
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:
|
||||
<%= PoolExample("PooledQueuedExecutor.cs", "activate") %>
|
||||
even if a <literal>QueuedExecutor</literal> restarts itself as
|
||||
needed and so a valid implementation could leave this method empty.
|
||||
</para>
|
||||
<para>
|
||||
After activation, and before the pooled object can be succesfully
|
||||
returned to the client, it is validated (should the object be
|
||||
invalid, it will be discarded: this can lead to an empty unusable
|
||||
pool
|
||||
<footnote>
|
||||
<para>You may think that we can provide a smarter
|
||||
implementation and you are probably right. However, it is not so
|
||||
difficult to create a new pool in case the old one became unusable.
|
||||
It could not be your preferred choice but surely it leverages
|
||||
simplicity and object immutability
|
||||
</para>
|
||||
</footnote>).
|
||||
Here we check that the worker thread exists:
|
||||
<%= PoolExample("PooledQueuedExecutor.cs", "validate") %>
|
||||
</para>
|
||||
<para>
|
||||
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:
|
||||
<%= PoolExample("PooledQueuedExecutor.cs", "passivate") %>
|
||||
</para>
|
||||
<para>
|
||||
At this point, creating a pool is simply a matter of creating an
|
||||
<literal>SimplePool</literal> as in:
|
||||
<%= PoolExample("PooledQueuedExecutor.cs", "create-pool") %>
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Being smart using pooled objects</title>
|
||||
<para>
|
||||
Taking advantage of the <literal>using</literal> keyword seems
|
||||
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:
|
||||
<%= PoolExample("PooledQueuedExecutor.cs", "execute") %>
|
||||
without worrying about obtaining and returning an object from/to the
|
||||
pool.
|
||||
</para>
|
||||
<para>
|
||||
Here is the implementation:
|
||||
<%= PoolExample("PooledQueuedExecutor.cs", "holder") %>
|
||||
</para>
|
||||
<para>
|
||||
Please don't forget to destroy all the pooled istances once you have
|
||||
finished! How? Well using something like this in
|
||||
<literal>PooledQueuedExecutor</literal>:
|
||||
<%= PoolExample("PooledQueuedExecutor.cs", "stop") %>
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Using the executor to do a parallel <literal>grep</literal></title>
|
||||
<para>
|
||||
The use of the just built executor is quite straigtforward but a
|
||||
little tricky if we want to really exploit the pool.
|
||||
<%= PoolExample("Grep.cs", "parallel-grep-class") %>
|
||||
</para>
|
||||
<para>
|
||||
<%= PoolExample("Grep.cs", "parallel-grep-main") %>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
37
doc/reference/src/templated/properties.props
Normal file
37
doc/reference/src/templated/properties.props
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="us-ascii"?>
|
||||
<codeSmith>
|
||||
<propertySet>
|
||||
<!--
|
||||
<property name="MyPurchaseOrder">
|
||||
<PurchaseOrder xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.ericjsmith.net">
|
||||
<ShipTo Name="Eric J. Smith">
|
||||
<Line1>123 Test Dr.</Line1>
|
||||
<City>Dallas</City>
|
||||
<State>TX</State>
|
||||
<Zip>75075</Zip>
|
||||
</ShipTo>
|
||||
<OrderDate>05-01-2003</OrderDate>
|
||||
<Items>
|
||||
<OrderedItem>
|
||||
<ItemName>Item #1</ItemName>
|
||||
<Description>Item #1 Description</Description>
|
||||
<UnitPrice>5.45</UnitPrice>
|
||||
<Quantity>3</Quantity>
|
||||
<LineTotal>16.35</LineTotal>
|
||||
</OrderedItem>
|
||||
<OrderedItem>
|
||||
<ItemName>Item #2</ItemName>
|
||||
<Description>Item #2 Description</Description>
|
||||
<UnitPrice>12.75</UnitPrice>
|
||||
<Quantity>8</Quantity>
|
||||
<LineTotal>102.00</LineTotal>
|
||||
</OrderedItem>
|
||||
</Items>
|
||||
<SubTotal>45.23</SubTotal>
|
||||
<ShipCost>5.23</ShipCost>
|
||||
<TotalCost>50.46</TotalCost>
|
||||
</PurchaseOrder>
|
||||
</property>
|
||||
-->
|
||||
</propertySet>
|
||||
</codeSmith>
|
||||
441
doc/reference/src/templated/windows-service.xml
Normal file
441
doc/reference/src/templated/windows-service.xml
Normal file
@@ -0,0 +1,441 @@
|
||||
<%@ 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>
|
||||
Reference in New Issue
Block a user