Update of /cvsroot/springnet/Spring.Net/doc/reference/src
In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv11266
Modified Files:
aop.xml objects.xml remoting-quickstart.xml transaction.xml
tx-quickstart.xml web.xml webservices.xml
Log Message:
remove various todo placeholders
update txquickstart docs
Index: webservices.xml
===================================================================
RCS file: /cvsroot/springnet/Spring.Net/doc/reference/src/webservices.xml,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** webservices.xml 15 Oct 2007 23:32:33 -0000 1.12
--- webservices.xml 7 Dec 2007 07:32:36 -0000 1.13
***************
*** 330,335 ****
while applying any configured AOP advice.</para>
- <!-- TODO: insert a diagram showing the call chain here -->
-
<para>Effecting this setup is actually fairly straightforward; because
an AOP proxy is an object just like any other object, all you need to do
--- 330,333 ----
Index: transaction.xml
===================================================================
RCS file: /cvsroot/springnet/Spring.Net/doc/reference/src/transaction.xml,v
retrieving revision 1.22
retrieving revision 1.23
diff -C2 -d -r1.22 -r1.23
*** transaction.xml 28 Nov 2007 05:54:37 -0000 1.22
--- transaction.xml 7 Dec 2007 07:32:36 -0000 1.23
***************
*** 379,385 ****
<title>Low-level approach</title>
! <para>TODO. A utility class can be used to directly obtain a
connection/transaction pair that is aware of the transactional calling
! context and returns and pair suitable for that context.</para>
</sect2>
</sect1>
--- 379,388 ----
<title>Low-level approach</title>
! <para>A utility class can be used to directly obtain a
connection/transaction pair that is aware of the transactional calling
! context and returns and pair suitable for that context. The class
! ConnectionUtils contains the static method ConnectionTxPair
! GetConnectionTxPair(IDbProvider provider) which serves this
! purpose.</para>
</sect2>
</sect1>
***************
*** 1726,1730 ****
alternatively throw an exception. This is shown below</para>
! <programlisting>TODO</programlisting>
<para>If you are using .NET 1.1 then you should provide a normal
--- 1729,1739 ----
alternatively throw an exception. This is shown below</para>
! <programlisting>tt.Execute(delegate(ITransactionStatus status)
! {
! adoTemplate.ExecuteNonQuery(CommandType.Text, "insert into dbo.Debits (DebitAmount) VALUES (@amount)", "amount", DbType.Decimal, 0,555);
! // decide you need to rollback...
! status.RollbackOnly = true;
! return null;
! });</programlisting>
<para>If you are using .NET 1.1 then you should provide a normal
***************
*** 1733,1737 ****
shown below</para>
! <programlisting>TODO</programlisting>
<para>Application classes wishing to use the
--- 1742,1765 ----
shown below</para>
! <programlisting>tt.Execute(new TransactionRollbackTxCallback(amount));
!
!
! public class TransactionRollbackTxCallback : ITransactionCallback
! {
! private decimal amount;
!
! public TransactionRollbackTxCallback(decimal amount)
! {
! this.amount = amount
! }
!
! public object DoInTransaction(ITransactionStatus status)
! {
! adoTemplate.ExecuteNonQuery(CommandType.Text, "insert into dbo.Debits (DebitAmount) VALUES (@amount)", "amount", DbType.Decimal, 0,555);
! // decide you need to rollback...
! status.RollbackOnly = true;
! return null;
! }
! }</programlisting>
<para>Application classes wishing to use the
***************
*** 1770,1774 ****
<para>Note that a corresponding 'using TransactionManagerScope' class
can be modeled to get similar API usage to System.Transactions
! TransactionScope. This will be done in a future release.</para>
</sect2>
</sect1>
--- 1798,1802 ----
<para>Note that a corresponding 'using TransactionManagerScope' class
can be modeled to get similar API usage to System.Transactions
! TransactionScope.</para>
</sect2>
</sect1>
Index: web.xml
===================================================================
RCS file: /cvsroot/springnet/Spring.Net/doc/reference/src/web.xml,v
retrieving revision 1.29
retrieving revision 1.30
diff -C2 -d -r1.29 -r1.30
*** web.xml 6 Dec 2007 17:51:57 -0000 1.29
--- web.xml 7 Dec 2007 07:32:36 -0000 1.30
***************
*** 1,3 ****
! <?xml version="1.0" encoding="UTF-8"?>
<chapter id="web">
<title>Spring.NET Web Framework</title>
--- 1,3 ----
! <?xml version="1.0" encoding="UTF-8"?>
<chapter id="web">
<title>Spring.NET Web Framework</title>
***************
*** 65,72 ****
mapping solves this problem by allowing application developers to specify
aliases for action results that map to target URLs based on information in
! an external configuration file that easily can be edited. Future releases
! of Spring.NET will also add a process management framework, which will
! take this approach to another level, allowing you to control complex page
! flows in a very simple way.</para>
<para>Standard localization support is also limited in versions of ASP.NET
--- 65,72 ----
mapping solves this problem by allowing application developers to specify
aliases for action results that map to target URLs based on information in
! an external configuration file that easily can be edited. Under
! consideration for future releases of Spring.NET is a process management
! framework, which will take this approach to another level, allowing you to
! control complex page flows in a very simple way.</para>
<para>Standard localization support is also limited in versions of ASP.NET
***************
*** 118,122 ****
uses many best practices for Spring.NET web applications, so please do
refer to it as you are reading this (reference) material (see <xref
! linkend="springair"/>).</para>
</sect1>
--- 118,122 ----
uses many best practices for Spring.NET web applications, so please do
refer to it as you are reading this (reference) material (see <xref
! linkend="springair" />).</para>
</sect1>
***************
*** 376,381 ****
hierarchy until it finds said object definition (or ultimately fails and
throws an exception).</para>
-
- <!-- TODO : insert diagram showing off the context hierarchy -->
</sect2>
</sect1>
--- 376,379 ----
***************
*** 1494,1498 ****
<note>
! The Visual Studio Web Form Editor will of course complain about binding attributes because it doesn't know them. You can safely ignore those warnings.
</note>
</sect2>
--- 1492,1496 ----
<note>
! The Visual Studio Web Form Editor will of course complain about binding attributes because it doesn't know them. You can safely ignore those warnings.
</note>
</sect2>
***************
*** 1623,1626 ****
--- 1621,1625 ----
<tip>
<title>VS2003</title>
+
<para>To view the .resx file for a page, you may need to enable
"Project/Show All Files" in Visual Studio.NET. When "Show All Files"
***************
*** 1635,1646 ****
select the "Source Code" text editor.</para>
</tip>
<tip>
<title>VS2005</title>
! <para>To create a resource file in VS2005, open your control or page in
! design mode and select "Tools/Generate local resource" from the menu</para>
</tip>
! <para>Finally a localizer must be configured for the page to enable automatic localization:
! </para>
<programlisting><object id="localizer" type="Spring.Globalization.Localizers.ResourceSetLocalizer, Spring.Core"/>
--- 1634,1649 ----
select the "Source Code" text editor.</para>
</tip>
+
<tip>
<title>VS2005</title>
!
! <para>To create a resource file in VS2005, open your control or page
! in design mode and select "Tools/Generate local resource" from the
! menu</para>
</tip>
! <para>Finally a localizer must be configured for the page to enable
! automatic localization:</para>
!
<programlisting><object id="localizer" type="Spring.Globalization.Localizers.ResourceSetLocalizer, Spring.Core"/>
***************
*** 1648,1652 ****
<property name="Localizer" ref="localizer"/>
</object></programlisting>
! <para>For more information on configuring localizers see <xref linkend="web-localizers" /></para>
</sect2>
--- 1651,1657 ----
<property name="Localizer" ref="localizer"/>
</object></programlisting>
!
! <para>For more information on configuring localizers see <xref
! linkend="web-localizers" /></para>
</sect2>
***************
*** 1654,1659 ****
<title>Global Message Sources</title>
! <para>The last two resource definitions from the previous section require some additional
! explanation:</para>
<programlisting><data name="$this.saveButton.Text">
--- 1659,1664 ----
<title>Global Message Sources</title>
! <para>The last two resource definitions from the previous section
! require some additional explanation:</para>
<programlisting><data name="$this.saveButton.Text">
***************
*** 1699,1705 ****
</object></programlisting>
! <important><title>NET 2.0</title>
! <para>To use resources from your App_GlobalResources folder, specify <literal>App_GlobalResources</literal> as assembly name (see the SpringAir example application for more):</para>
! <literal><value>Resources.Strings, App_GlobalResources</value></literal>
</important>
--- 1704,1716 ----
</object></programlisting>
! <important>
! <title>NET 2.0</title>
!
! <para>To use resources from your App_GlobalResources folder, specify
! <literal>App_GlobalResources</literal> as assembly name (see the
! SpringAir example application for more):</para>
!
! <literal><value>Resources.Strings,
! App_GlobalResources</value></literal>
</important>
***************
*** 1717,1721 ****
<para>Currently, the <literal>ResourceSetMessageSource</literal> is the
only message source implementation that ships with Spring.NET.</para>
-
</sect2>
--- 1728,1731 ----
***************
*** 1743,1754 ****
<classname>Spring.Globalization.Localizers.ResourceSetLocalizer</classname>,
that retrieves a list of resources to apply from the local resource
! file. Future releases of Spring.NET will provide other localizers that
! read resources from an XML file or even a flat text file that contains
! resource name-value pairs which will allow application developers to
! store resources within the files in a web application instead of as
! embedded resources in an assembly. Of course, if an application
! developer would rather store such resources in a database, he or she can
! write their own <classname>ILocalizer</classname> implementation that
! will load a list of resources to apply from a database.</para>
<para>As mentioned previously, one would typically configure the
--- 1753,1765 ----
<classname>Spring.Globalization.Localizers.ResourceSetLocalizer</classname>,
that retrieves a list of resources to apply from the local resource
! file. Future releases of Spring.NET may provide other localizers as a
! convienence that read resources from an XML file or even a flat text
! file that contains resource name-value pairs which will allow
! application developers to store resources within the files in a web
! application instead of as embedded resources in an assembly. Of course,
! if an application developer would rather store such resources in a
! database, he or she can write their own
! <classname>ILocalizer</classname> implementation that will load a list
! of resources to apply from a database.</para>
<para>As mentioned previously, one would typically configure the
***************
*** 1789,1793 ****
page. For example, think of the header columns for outgoing and return
flights tables within the SpringAir application (see <xref
! linkend="springair"/>).</para>
<para>In these situations, one should use a pull-style mechanism for
--- 1800,1804 ----
page. For example, think of the header columns for outgoing and return
flights tables within the SpringAir application (see <xref
! linkend="springair" />).</para>
<para>In these situations, one should use a pull-style mechanism for
***************
*** 2224,2229 ****
declaration is required in order for Spring.NET
<literal>Register*</literal> scripts to work properly.</para>
-
- <para>TODO : insert example</para>
</sect2>
--- 2235,2238 ----
***************
*** 2241,2246 ****
embedded <literal>style</literal> section of the final HTML
document.</para>
-
- <para>TODO : insert example</para>
</sect2>
--- 2250,2253 ----
Index: objects.xml
===================================================================
RCS file: /cvsroot/springnet/Spring.Net/doc/reference/src/objects.xml,v
retrieving revision 1.110
retrieving revision 1.111
diff -C2 -d -r1.110 -r1.111
*** objects.xml 6 Dec 2007 06:26:30 -0000 1.110
--- objects.xml 7 Dec 2007 07:32:36 -0000 1.111
***************
*** 1418,1426 ****
XML verbosity when setting collection properties. See <xref
linkend="objects-shortcutforms" /> for more information.</para>
-
- <para>Please be advised that the setting of multiple values for a
- <literal>NameValueCollection</literal> is <ulink
- url="http://opensource.atlassian.com/projects/spring/browse/SPRNET-58">planned
- for a future release.</ulink></para>
</sect3>
--- 1418,1421 ----
Index: remoting-quickstart.xml
===================================================================
RCS file: /cvsroot/springnet/Spring.Net/doc/reference/src/remoting-quickstart.xml,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** remoting-quickstart.xml 15 Oct 2007 23:32:33 -0000 1.12
--- remoting-quickstart.xml 7 Dec 2007 07:32:36 -0000 1.13
***************
*** 478,483 ****
</programlisting></para>
- <para>TODO: Show use of custom .net remoting schema.</para>
-
<para>You must specify the property <literal>ServiceInterface</literal> as
well as the location of the remote object via the
--- 478,481 ----
***************
*** 725,729 ****
</objects></programlisting>The configuraiton file webService.xml
! simply exports the named calculator object </para>
<programlisting> <object id="calculatorService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
--- 723,727 ----
</objects></programlisting>The configuraiton file webService.xml
! simply exports the named calculator object</para>
<programlisting> <object id="calculatorService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
Index: tx-quickstart.xml
===================================================================
RCS file: /cvsroot/springnet/Spring.Net/doc/reference/src/tx-quickstart.xml,v
retrieving revision 1.6
retrieving revision 1.7
diff -C2 -d -r1.6 -r1.7
*** tx-quickstart.xml 17 Oct 2007 17:51:07 -0000 1.6
--- tx-quickstart.xml 7 Dec 2007 07:32:36 -0000 1.7
***************
*** 11,15 ****
the use of declarative transactions using attributes and also the ability
to change the transaction manager (local or distributed) via changes to
! only the configuration files - no code changes are required.</para>
</section>
--- 11,25 ----
the use of declarative transactions using attributes and also the ability
to change the transaction manager (local or distributed) via changes to
! only the configuration files - no code changes are required. It also
! demonstrates some techniques for unit and integration testing an
! appliation as well as separating Spring's configuration files so that one
! is responsible for describing how the core business classes are configured
! and others that are responsbile for the database environment and
! application of AOP.</para>
!
! <para>This quickstart assumes you have installed a way to run NUnit tests
! within your IDE. Some excellent tools that let you do this are <ulink
! url="http://www.testdriven.net/">TestDriven.NET</ulink> and <ulink
! url="http://www.jetbrains.com/resharper/">ReSharper</ulink>.</para>
</section>
***************
*** 29,44 ****
implementation <classname>AccountManager</classname> located in the
namespace <classname>Spring.TxQuickStart.Services</classname>. The money
! is 'contained' in a credit table and a debit table in the database. The
! SQL Server schema for the tables is located in the file
! CreditsDebitsSchema.sql. Transferring the money requires an ACID operation
! on these two tables. The credit operation is defined via a
<interfacename>IAccountCreditDao</interfacename> interface and the debit
operation via an <interfacename>IAccountDebitDao</interfacename>
! interface. Implementations based on <classname>AdoTemplate</classname> are
! in the namespace <package>Spring.TxQuickStart.Dao.Ado</package>. Note that
! Spring's transaction management framework allows the mixing of data access
! technologies within the same transaction, i.e. ORM and ADO.NET. A
! demonstration of this features will be added to this quick start in a
! future release.</para>
<section>
--- 39,51 ----
implementation <classname>AccountManager</classname> located in the
namespace <classname>Spring.TxQuickStart.Services</classname>. The money
! is recorded in a credit and debit table in the database. The SQL Server
! schema for the tables is located in the file CreditsDebitsSchema.sql.
! Transferring the money requires an ACID operation on these two tables. The
! credit operation is defined via a
<interfacename>IAccountCreditDao</interfacename> interface and the debit
operation via an <interfacename>IAccountDebitDao</interfacename>
! interface. Implementations of these interfaces using
! <classname>AdoTemplate</classname> are in the namespace
! <package>Spring.TxQuickStart.Dao.Ado</package>. </para>
<section>
***************
*** 62,67 ****
void DebitAccount(float debitAmount);
}</programlisting>
-
- <para></para>
</section>
</section>
--- 69,72 ----
***************
*** 77,82 ****
{
AdoTemplate.ExecuteNonQuery(CommandType.Text,
! String.Format("insert into Credits (CreditAmount) VALUES ({0})",
! creditAmount));
}
}</programlisting>
--- 82,87 ----
{
AdoTemplate.ExecuteNonQuery(CommandType.Text,
! "insert into Credits (CreditAmount) VALUES (@amount)", "amount", DbType.Decimal, 0,
! creditAmount);
}
}</programlisting>
***************
*** 89,144 ****
{
AdoTemplate.ExecuteNonQuery(CommandType.Text,
! String.Format("insert into dbo.Debits (DebitAmount) VALUES ({0})",
! debitAmount));
}
}</programlisting>
<para>Both of these DAO implementations inherit from Spring's
! AdoDaoSupport class that provides convenient access to an AdoTemplate for
! performing data access operations. With no other properties that can be
! configured in these implementations, the only configuration required is
! setting of AdoDaoSupport's DbProvider property representing the connection
! to the database.</para>
! <para>The implementation of the service layer class, IAccountManager, is
! show below with extraneous declarations of properties for the DAO objects
! and boolean 'throwException' property.</para>
<programlisting> public class AccountManager : IAccountManager
{
! // fields and properties for DAO objects and boolean throwException not shown
[Transaction]
public void DoTransfer(float creditAmount, float debitAmount)
{
! creditDao.CreateCredit(creditAmount);
! if (ThrowException)
{
! throw new ArithmeticException("Couldn't do the math....");
}
!
! debitDao.DebitAccount(debitAmount);
}
}</programlisting>
! <para>The throw exception property, if true, will throw the shown
! exception and is used to demonstrate rollback behavior. Note the
! Transaction annotation above the method. This will be read by Spring and
! used to create a transactional proxy to AccountManager in order to perform
! declarative transaction management.</para>
! <para>The driver for the program is an NUnit test. It is convenient to
! download a VS.NET add-in, such as TestDriven.NET or Resharper to be able
! to run the unit test from within VS.NET. The code for the unit test driver
! is shown below</para>
<programlisting> [TestFixture]
public class AccountManagerTests
{
! private IApplicationContext ctx;
[SetUp]
--- 94,236 ----
{
AdoTemplate.ExecuteNonQuery(CommandType.Text,
! "insert into dbo.Debits (DebitAmount) VALUES (@amount)", "amount", DbType.Decimal, 0,
! debitAmount);
}
}</programlisting>
<para>Both of these DAO implementations inherit from Spring's
! <classname>AdoDaoSupport</classname> class that provides convenient access
! to an <classname>AdoTemplate</classname> for performing data access
! operations. With no other properties that can be configured in these
! implementations, the only configuration required is setting of
! AdoDaoSupport's <classname>DbProvider</classname> property representing
! the connection to the database.</para>
! <para>The implementation of the service layer interface,
! <classname>IAccountManager</classname>, is shown below.</para>
<programlisting> public class AccountManager : IAccountManager
{
! private IAccountCreditDao accountCreditDao;
! private IAccountDebitDao accountDebitDao;
!
! private float maxTransferAmount = 1000000;
!
! public AccountManager(IAccountCreditDao accountCreditDao, IAccountDebitDao accountDebitDao)
! {
! this.accountCreditDao = accountCreditDao;
! this.accountDebitDao = accountDebitDao;
! }
+ public float MaxTransferAmount
+ {
+ get { return maxTransferAmount; }
+ set { maxTransferAmount = value; }
+ }
+
[Transaction]
public void DoTransfer(float creditAmount, float debitAmount)
{
! accountCreditDao.CreateCredit(creditAmount);
! if (creditAmount > maxTransferAmount || debitAmount > maxTransferAmount)
{
! throw new ArithmeticException("see a teller big spender...");
}
!
! accountDebitDao.DebitAccount(debitAmount);
}
}</programlisting>
! <para>The if statement is a poor-mans representation of business logic,
! namely that there is a policy that does not allow the use of this service
! for amounts larger than $1,000,000. If the credit or debit amount is
! larger than 1,000,000 then and exception will be thrown. We can write a
! unit test that will test for this business logic and provide stub
! implementations of the DAO objects so that our tests are not only
! independent of the database but will also execute very quickly.<note>
! <para>Notice the Transaction attribute on the
! <literal>DoTransfer</literal> method. This attribute be read by Spring
! and used to create a transactional proxy to AccountManager in order to
! perform declarative transaction management.</para>
! </note></para>
! <para>The NUnit unit test for AccountManager is shown below</para>
!
! <programlisting> public class AccountManagerUnitTests
! {
! private IAccountManager accountManager;
!
! [SetUp]
! public void Setup()
! {
! IAccountCreditDao stubCreditDao = new StubAccountCreditDao();
! IAccountDebitDao stubDebitDao = new StubAccountDebitDao();
! accountManager = new AccountManager(stubCreditDao, stubDebitDao);
! }
!
! [Test]
! public void TransferBelowMaxAmount()
! {
! accountManager.DoTransfer(217, 217);
! }
!
! [Test]
! [ExpectedException(typeof(ArithmeticException))]
! public void TransferAboveMaxAmount()
! {
! accountManager.DoTransfer(2000000, 200000);
! }
! }</programlisting>
!
! <para>Running these tests we exercise both code pathways through the
! method <literal>DoTransfer</literal>. Nothing we have done so far is
! Spring specifc (aside from the presense of the [Transation] attribute. Now
! that we know the class works in isolation, we can now 'wire' up the
! application for use in production by specifying how the service and dao
! layers are related. This configuration file is shown below and can loosely
! be referred to as your 'appliation blueprint'. This configuration file is
! named application-config.xml and is an embedded resource inside the 'main'
! project, Spring.TxQuickStart.</para>
!
! <programlisting><objects xmlns='http://www.springframework.net'>
!
! <!-- DAO Implementations -->
! <object id="accountCreditDao" type="Spring.TxQuickStart.Dao.Ado.AccountCreditDao, Spring.TxQuickStart">
! <property name="DbProvider" ref="CreditDbProvider"/>
! </object>
!
! <object id="accountDebitDao" type="Spring.TxQuickStart.Dao.Ado.AccountDebitDao, Spring.TxQuickStart">
! <property name="DbProvider" ref="DebitDbProvider"/>
! </object>
!
!
! <!-- The service that performs multiple data access operations -->
! <object id="accountManager"
! type="Spring.TxQuickStart.Services.AccountManager, Spring.TxQuickStart">
! <constructor-arg name="accountCreditDao" ref="accountCreditDao"/>
! <constructor-arg name="accountDebitDao" ref="accountDebitDao"/>
! </object>
!
! </objects></programlisting>
!
! <para>This configuration is selecting the real ADO.NET implementations
! that will insert records into the database. We can now write a NUnit
! integration test that will test the service and DAO layers. To do this we
! add on configuration information specific to our test environment. This
! extran configuration information will determine what databases we speak to
! and what transaction manager (local or distribute) to use. The code for
! this integration style NUnit test is shown below</para>
<programlisting> [TestFixture]
public class AccountManagerTests
{
! private AdoTemplate adoTemplateCredit;
! private AdoTemplate adoTemplateDebit;
!
! private IAccountManager accountManager;
[SetUp]
***************
*** 149,175 ****
NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser));
NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));
! string ctxName = "DTCAppContext.xml"; // for .NET 2.0
! //string ctxName = "DTC1.1AppContext.xml"; // for .NET 1.1
! ctx = new XmlApplicationContext(
! "assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/" + ctxName);
}
[Test]
! public void DeclarativeWithAttributes()
{
! IAccountManager mgr = ctx["accountManager"] as IAccountManager;
! mgr.DoTransfer(217, 217);
}
}</programlisting>
<para>The essential element is to create an instance of Spring's
application context where the relevant layers of the application are
! 'wired' together. The top level object for the purposes of this quick
! start is the account manager, which is retrieved from Spring's application
! context and the method DoTransfer is executed.</para>
!
! <para>Note, future releases will instead have as the driver program a
! console application.</para>
</section>
--- 241,294 ----
NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser));
NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));
! IApplicationContext context = new XmlApplicationContext(
! "assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/system-test-local-config.xml"
! );
! accountManager = context["accountManager"] as IAccountManager;
! CleanDb(context);
}
[Test]
! public void TransferBelowMaxAmount()
{
! accountManager.DoTransfer(217, 217);
!
! int numCreditRecords = (int)adoTemplateCredit.ExecuteScalar(CommandType.Text, "select count(*) from Credits");
! int numDebitRecords = (int)adoTemplateDebit.ExecuteScalar(CommandType.Text, "select count(*) from Debits");
! Assert.AreEqual(1, numCreditRecords);
! Assert.AreEqual(1, numDebitRecords);
! }
!
! [Test]
! [ExpectedException(typeof(ArithmeticException))]
! public void TransferAboveMaxAmount()
! {
! accountManager.DoTransfer(2000000, 200000);
}
+
+ private void CleanDb(IApplicationContext context)
+ {
+ IDbProvider dbProvider = (IDbProvider)context["DebitDbProvider"];
+ adoTemplateDebit = new AdoTemplate(dbProvider);
+ adoTemplateDebit.ExecuteNonQuery(CommandType.Text, "truncate table Debits");
+
+ dbProvider = (IDbProvider)context["CreditDbProvider"];
+ adoTemplateCredit = new AdoTemplate(dbProvider);
+ adoTemplateCredit.ExecuteNonQuery(CommandType.Text, "truncate table Credits");
+
+ }
}</programlisting>
<para>The essential element is to create an instance of Spring's
application context where the relevant layers of the application are
! 'wired' together. The <classname>IAccountManager</classname>
! implementation is retrieved from the IoC container and stored as a field
! of the test class. The basic logic of the test are the same as in the unit
! test but in addtion there is the verification of actions performed in the
! database. The setup method puts the database tables into a known state
! before running the tests. Other techniques for performing integration
! testing that can alleviate the need to extensive database state management
! for integration tests is described in the <link
! linkend="testing">testing</link> section.</para>
</section>
***************
*** 177,272 ****
<title>Configuration</title>
! <para>The configuration for application is shown below</para>
! <programlisting><objects xmlns='http://www.springframework.net'
xmlns:db="http://www.springframework.net/database"
! xmlns:tx="http://www.springframework.net/tx"
! xmlns:aop="http://www.springframework.net/aop">
- <!-- <emphasis role="bold">Database Providers </emphasis>-->
<db:provider id="DebitDbProvider"
! provider="System.Data.SqlClient"
! connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=Debits;User ID=springqa; Password=springqa"/>
<db:provider id="CreditDbProvider"
! provider="System.Data.SqlClient"
! connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=Credits;User ID=springqa; Password=springqa"/>
!
!
! <!-- <emphasis role="bold">Transaction Manager</emphasis> if using two databases, one containing the credit table and the other a debit table -->
!
! <object id="transactionManager"
! type="Spring.Data.Core.TxScopeTransactionManager, Spring.Data">
! </object>
!
!
! <!-- <emphasis role="bold">DAO Layer</emphasis> -->
!
! <object id="accountCreditDao" type="Spring.TxQuickStart.Dao.Ado.AccountCreditDao, Spring.TxQuickStart">
! <property name="DbProvider" ref="CreditDbProvider"/>
! </object>
! <object id="accountDebitDao" type="Spring.TxQuickStart.Dao.Ado.AccountDebitDao, Spring.TxQuickStart">
<property name="DbProvider" ref="DebitDbProvider"/>
</object>
!
! <!-- <emphasis role="bold">The service layer</emphasis> that performs multiple data access operations -->
! <object id="accountManager"
! type="Spring.TxQuickStart.Services.AccountManager, Spring.TxQuickStart">
! <property name="AccountCreditDao" ref="accountCreditDao"/>
! <property name="AccountDebitDao" ref="accountDebitDao"/>
! <property name="ThrowException" value="false"/>
! </object>
!
! <!-- <emphasis role="bold">Enable declarative transaction management</emphasis> -->
!
<tx:attribute-driven/>
</objects></programlisting>
! <para>Moving from top to bottom in th configuration file, the database
! type and connection parameters are first specified for the two databases.
! The type of transaction manager is then selected, in this case we are
! showing the use of TxScopeTransactionManager that uses .NET 2.0
! System.Transactions as the implementation, allowing for distributed
! transactions between the two different databases listed. The DAO layer is
! then configured with each DAO object referring to its appropriate
! database. The service layer then ties together the two DAO objects and
! configures the AccountManager not to throw exceptions. Lastly, declarative
! transaction management through the use of attributes is enable. In a
! larger application the different layers would typically be broken up into
! individual configuration files and imported into the main configuration
! file. This allows your configuration to mirror your architecture.</para>
! <para>Running the tests will result in 217 being entered into the Credits
! and Debits table of each database. You should fire up SQL Server
! Management Studio or equivalent to verify this. It is also interesting to
! view the distributed transaction monitor that is part of the Component
! Services GUI. If you change the property ThrowException to true, and
! re-run the test, then you will not have the value 217 entered in either
! table.</para>
! <para>If we need to switch from distributed transactions to local
! transactions with a single database, then all that needs to change is the
! configuration of the database providers as well as selecting a different
! transaction manager. The application code does not need to change. The
! configuration to use a single database is listed below</para>
! <programlisting> <db:provider id="DebitDbProvider"
provider="System.Data.SqlClient"
! connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"/>
<db:provider id="CreditDbProvider"
provider="System.Data.SqlClient"
! connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"/>
! <object id="transactionManager"
! type="Spring.Data.AdoPlatformTransactionManager, Spring.Data">
! <property name="DbProvider" ref="DbProvider"/>
! </object></programlisting>
! <para>Notice that the Initial Catalog value has changed.</para>
<section>
--- 296,403 ----
<title>Configuration</title>
! <para>The configuration file system-test-local-config.xml shown in the
! previous program listing includes application-config.xml and specifies the
! database to use and the local (not distributed) transaction manager
! AdoPlatformTransactionManager. This configuration file is shown
! below</para>
! <programlisting><objects xmlns="http://www.springframework.net"
xmlns:db="http://www.springframework.net/database"
! xmlns:tx="http://www.springframework.net/tx">
+ <!-- Imports application configuration -->
+ <import resource="assembly://Spring.TxQuickStart/Spring.TxQuickStart/application-config.xml"/>
+
+ <!-- Imports additional aspects -->
+ <!--
+ <import resource="assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/aspects-config.xml"/>
+ -->
+
+
+ <!-- Database Providers -->
+
<db:provider id="DebitDbProvider"
! provider="System.Data.SqlClient"
! connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"/>
<db:provider id="CreditDbProvider"
! provider="System.Data.SqlClient"
! connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"/>
!
! <alias name="DebitDbProvider" alias="CreditDbProvider"/>
! <!-- Transaction Manager if using a single database that contain both credit and debit tables -->
! <object id="transactionManager"
! type="Spring.Data.Core.AdoPlatformTransactionManager, Spring.Data">
<property name="DbProvider" ref="DebitDbProvider"/>
</object>
! <!-- Transaction aspect -->
!
<tx:attribute-driven/>
</objects></programlisting>
! <para>Moving from top to bottom in th configuration file, the
! 'application-blueprint' configuration file is included. Then the database
! type and connection parameters are specified for the two databases. The
! names of these provides must match those specific in
! application-config.xml. Since the two names point to the same database, an
! alias configuration element is used to have them point to the same
! dbProvider under different names. The type of transaction manager is then
! selected, in this case we are showing the use of local tansactions with
! AdoPlatformTransactionManager. Running the tests will result in 217 being
! entered into the Credits and Debits table of each database. You can fire
! up SQL Server Management Studio or equivalent to verify this.</para>
! <para>To switch to distributed transaction you can refer to the
! configuration file system-test-dtc-config.xml, which is shown below</para>
! <programlisting>objects xmlns='http://www.springframework.net'
! xmlns:db="http://www.springframework.net/database"
! xmlns:tx="http://www.springframework.net/tx">
!
! <!-- Imports application configuration -->
! <import resource="assembly://Spring.TxQuickStart/Spring.TxQuickStart/application-config.xml"/>
!
! <!-- Imports additional aspects -->
! <!--
! <import resource="assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/aspects-config.xml"/>
! -->
!
! <db:provider id="DebitDbProvider"
provider="System.Data.SqlClient"
! connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=Debits;User ID=springqa; Password=springqa"/>
!
<db:provider id="CreditDbProvider"
provider="System.Data.SqlClient"
! connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=Credits;User ID=springqa; Password=springqa"/>
!
!
! <!-- Transaction Manager if using two databases, one containing the credit table and the other a debit table -->
! <object id="transactionManager"
! type="Spring.Data.Core.TxScopeTransactionManager, Spring.Data">
! </object>
!
! <!-- Transaction aspect -->
! <tx:attribute-driven/>
!
! </objects></programlisting>
!
! <para>TxScopeTransactionManager uses .NET 2.0 System.Transactions as the
! implementation, allowing for distributed transactions between the two
! different databases listed. In a larger application the different layers
! would typically be broken up into individual configuration files and
! imported into the main configuration file. This allows your configuration
! to mirror your architecture.</para>
!
! <para>You can also use the configuraiton file
! system-test-dtc-es-config.xml that will use EnterpriseServices to perform
! transaction management.</para>
<section>
***************
*** 279,309 ****
shown below.</para>
! <programlisting> [Transaction(NoRollbackFor = new Type[] { typeof(ApplicationException) })]
public void DoTransfer(float creditAmount, float debitAmount)
{
! creditDao.CreateCredit(creditAmount);
! DoThrowException();
! debitDao.DebitAccount(debitAmount);
! }
! public void DoThrowException()
! {
! throw new ApplicationException("Testing No Rollback 'Rule'");
! }</programlisting>
<para>The expected behavior is that the credit table will be updated
even though the exception is thrown. This is due to specifying that
! exceptions of the type ApplicationException should not rollback the
database transaction. Running the test code below, verifies that the
! exception still propagates out of the method. Use SQL Server Management
! Studio or equivalent to verify the state of the Credit and Debit
! table.</para>
<programlisting> [Test]
- [ExpectedException(typeof(ApplicationException), "Testing No Rollback 'Rule'")]
public void DeclarativeWithAttributesNoRollbackFor()
{
! IAccountManager mgr = ctx["accountManager"] as IAccountManager;
! mgr.DoTransfer(314, 314);
}</programlisting>
</section>
--- 410,448 ----
shown below.</para>
! <programlisting> [Transaction(NoRollbackFor = new Type[] { typeof(ArithmeticException) })]
public void DoTransfer(float creditAmount, float debitAmount)
{
! accountCreditDao.CreateCredit(creditAmount);
! if (creditAmount > maxTransferAmount || debitAmount > maxTransferAmount)
! {
! throw new ArithmeticException("see a teller big spender...");
! }
!
! accountDebitDao.DebitAccount(debitAmount);
! } </programlisting>
!
! <para>All that has changed is the use of the NoRollbackFor property on
! the transaction attribute.</para>
<para>The expected behavior is that the credit table will be updated
even though the exception is thrown. This is due to specifying that
! exceptions of the type ArithmethicException should not rollback the
database transaction. Running the test code below, verifies that the
! exception still propagates out of the method. </para>
<programlisting> [Test]
public void DeclarativeWithAttributesNoRollbackFor()
{
! try
! {
! accountManager.DoTransfer(2000000, 2000000);
! Assert.Fail("Should have thrown Arithmethic Exception");
! } catch (ArithmeticException) {
! int numCreditRecords = (int)adoTemplateCredit.ExecuteScalar(CommandType.Text, "select count(*) from Credits");
! int numDebitRecords = (int)adoTemplateDebit.ExecuteScalar(CommandType.Text, "select count(*) from Debits");
! Assert.AreEqual(1, numCreditRecords);
! Assert.AreEqual(0, numDebitRecords);
! }
}</programlisting>
</section>
***************
*** 318,327 ****
program methods that have the Transaction attribute applied. In this
example we will add logging of thrown exceptions using Spring's
! ExceptionHandlerAdvice. No code is required to be changed in order to have
! this additional functionality. Instead modify the configuration to the
! following</para>
- <programlisting>
- <tx:attribute-driven order="10"/>
<object name="exceptionAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
--- 457,475 ----
program methods that have the Transaction attribute applied. In this
example we will add logging of thrown exceptions using Spring's
! ExceptionHandlerAdvice as well logging of the service layer method
! invocation. No code is required to be changed in order to have this
! additional functionality. Instead all you have to do is uncomment the
! line</para>
!
! <programlisting> <import resource="assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/aspects-config.xml"/></programlisting>
!
! <para> in either system-test-dtc-config.xml or
! system-test-local-config.xml The aspect configuration file is shown
! below</para>
!
! <programlisting><objects xmlns='http://www.springframework.net'
! xmlns:aop="http://www.springframework.net/aop">
!
<object name="exceptionAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
***************
*** 333,336 ****
--- 481,497 ----
</object>
+ <object name="loggingAdvice" type="Spring.Aspects.Logging.SimpleLoggingAdvice, Spring.Aop">
+ <property name="logUniqueIdentifier" value="true"/>
+ <property name="logExecutionTime" value="true"/>
+ <property name="logMethodArguments" value="true"/>
+ <property name="Separator" value=";"/>
+
+ <property name="HideProxyTypeNames" value="true"/>
+ <property name="UseDynamicLogger" value="true"/>
+
+ <property name="LogLevel" value="Info"/>
+ </object>
+
+
<object id="txAttributePointcut" type="Spring.Aop.Support.AttributeMatchMethodPointcut, Spring.Aop">
<property name="Attribute" value="Spring.Transaction.Interceptor.TransactionAttribute, Spring.Data"/>
***************
*** 338,345 ****
<aop:config>
<aop:advisor id="exceptionProcessAdvisor" order="1"
! advice-ref="exceptionAdvice"
pointcut-ref="txAttributePointcut"/>
! </aop:config></programlisting>
<para>The transaction aspect is now additionally configured with an order
--- 499,514 ----
<aop:config>
+
<aop:advisor id="exceptionProcessAdvisor" order="1"
! advice-ref="exceptionAdvice"
! pointcut-ref="txAttributePointcut"/>
!
! <aop:advisor id="loggingAdvisor" order="2"
! advice-ref="loggingAdvice"
pointcut-ref="txAttributePointcut"/>
!
! </aop:config>
!
! </objects></programlisting>
<para>The transaction aspect is now additionally configured with an order
***************
*** 350,361 ****
<classname>Spring.Aspects.Exceptions.ExceptionHandlerAdvice</classname>.
The location where that behavior is applied, the pointcut, is the
! Transaction attribute. The aop configuration section on the bottom is what
! ties together the behavior and where it will take place in the program
! flow. Under the covers the transaction configuration,
! <tx:attribute-driven/> creates similar advice and pointcut
! definitions. Setting the ThrowException property of AccountManager to
! true, you will see in the log file the message</para>
! <programlisting>LogExceptionHandler - Logging an exception thrown from method DoTransfer
</programlisting>
--- 519,551 ----
<classname>Spring.Aspects.Exceptions.ExceptionHandlerAdvice</classname>.
The location where that behavior is applied, the pointcut, is the
! Transaction attribute. The logging of method arguments and execution time
! is specified by configuring an instance of
! <classname>Spring.Aspects.Logging.SimpleLoggingAdvice</classname>.</para>
! <para>The AOP configuration section on the bottom is what ties together
! the behavior and where it will take place in the program flow. Under the
! covers the transaction configuration, <tx:attribute-driven/> creates
! similar advice and pointcut definitions. Running the test
! TransferBelowMaxAmount will then log the following messages</para>
!
! <programlisting>INFO - Entering DoTransfer;45b6af04-b736-4efa-a489-45462726ddf2;creditAmount=217; debitAmount=217
! INFO - Exiting DoTransfer;45b6af04-b736-4efa-a489-45462726ddf2;1328.125 ms;return=
! </programlisting>
!
! <para>When the test case of the test TransferAboveMaxAmount is run the
! following messages are logged</para>
!
! <programlisting>INFO - Entering DoTransfer;d94bc81b-a4ff-4ca1-9aaa-f2834f262307;creditAmount=2000000; debitAmount=200000
! INFO - Exception thrown in DoTransferDoTransfer;d94bc81b-a4ff-4ca1-9aaa-f2834f262307;1140.625
! System.ArithmeticException: see a teller big spender...
! at Spring.TxQuickStart.Services.AccountManager.DoTransfer(Single creditAmount, Single debitAmount) in L:\projects\Spring.Net\examples\Spring\Spring.TxQuickStart\src\Spring\Spring.TxQuickStart\TxQuickStart\Services\AccountManager.cs:line 36
! at Spring.DynamicReflection.Method_DoTransfer_ec48557f22b149958fd2243413136600.Invoke(Object target, Object[] args)
! at Spring.Reflection.Dynamic.SafeMethod.Invoke(Object target, Object[] arguments) in l:\projects\Spring.Net\src\Spring\Spring.Core\Reflection\Dynamic\DynamicMethod.cs:line 108
! at Spring.Aop.Framework.DynamicMethodInvocation.InvokeJoinpoint() in l:\projects\Spring.Net\src\Spring\Spring.Aop\Aop\Framework\DynamicMethodInvocation.cs:line 89
! at Spring.Aop.Framework.AbstractMethodInvocation.Proceed() in l:\projects\Spring.Net\src\Spring\Spring.Aop\Aop\Framework\AbstractMethodInvocation.cs:line 257
! at Spring.Transaction.Interceptor.TransactionInterceptor.Invoke(IMethodInvocation invocation) in l:\projects\Spring.Net\src\Spring\Spring.Data\Transaction\Interceptor\TransactionInterceptor.cs:line 80
! at Spring.Aop.Framework.AbstractMethodInvocation.Proceed() in l:\projects\Spring.Net\src\Spring\Spring.Aop\Aop\Framework\AbstractMethodInvocation.cs:line 282
! at Spring.Aspects.Logging.SimpleLoggingAdvice.InvokeUnderLog(IMethodInvocation invocation, ILog log) in l:\projects\Spring.Net\src\Spring\Spring.Aop\Aspects\Logging\SimpleLoggingAdvice.cs:line 185
! TRACE - Logging an exception thrown from method DoTransfer
</programlisting>
Index: aop.xml
===================================================================
RCS file: /cvsroot/springnet/Spring.Net/doc/reference/src/aop.xml,v
retrieving revision 1.46
retrieving revision 1.47
diff -C2 -d -r1.46 -r1.47
*** aop.xml 27 Nov 2007 21:01:42 -0000 1.46
--- aop.xml 7 Dec 2007 07:32:36 -0000 1.47
***************
*** 266,270 ****
that are most common targets for AOP proxies.</para>
! <para>In the future release we will implement proxies using inheritance,
which will allow you to proxy classes without interfaces as well and
will remove some of the remaining raw reference issues that cannot be
--- 266,270 ----
that are most common targets for AOP proxies.</para>
! <para>In a future release we will implement proxies using inheritance,
which will allow you to proxy classes without interfaces as well and
will remove some of the remaining raw reference issues that cannot be
***************
*** 1548,1553 ****
<para>You can add interceptors or advisors, and manipulate them for the
! life of the <literal>ProxyFactory</literal>. <emphasis>TODO: note on
! introductions.</emphasis></para>
<para>There are also convenience methods on
--- 1548,1552 ----
<para>You can add interceptors or advisors, and manipulate them for the
! life of the <literal>ProxyFactory.</literal></para>
<para>There are also convenience methods on
***************
*** 1627,1635 ****
<para>By default, it's possible to add or remove advisors or interceptors
! even once a proxy has been created. <emphasis>TODO: Need to query this for
! introductions</emphasis> The only restriction is that it's impossible to
! add or remove an introduction advisor, as existing proxies from the
! factory will not show the interface change. (You can obtain a new proxy
! from the factory to avoid this problem.)</para>
<remark>It's questionable whether it's advisable (no pun intended) to
--- 1626,1633 ----
<para>By default, it's possible to add or remove advisors or interceptors
! even once a proxy has been created. The only restriction is that it's
! impossible to add or remove an introduction advisor, as existing proxies
! from the factory will not show the interface change. (You can obtain a new
! proxy from the factory to avoid this problem.)</para>
<remark>It's questionable whether it's advisable (no pun intended) to
***************
*** 2084,2088 ****
programmatic or through XML based configuration.</para>
! <para>TODO: Example based on transaction attributes.</para>
</sect2>
</sect1>
--- 2082,2088 ----
programmatic or through XML based configuration.</para>
! <para>Several of the aspect provided with Spring use attribute driven
! autoproxying. The most prominent example is <link
! linkend="transactions">Transaction</link> support.</para>
</sect2>
</sect1>
|