From 878c3aba06d3d653669d66e86e5f31eb89ee1585 Mon Sep 17 00:00:00 2001 From: markpollack Date: Tue, 3 Nov 2009 23:11:22 +0000 Subject: [PATCH] SPRNET-1266 - Context creation can throw ObjectCurrentlyInCreatation exception thrown when using with NHibernateTransactionManager --- .../Spring.Data/Spring.Data.2008.csproj | 4 +- .../AttributeDrivenObjectDefinitionParser.cs | 38 ++++++---- ...tractTransactionAttributeSourcePointcut.cs | 59 +++++++++++++++ ...actoryTransactionAttributeSourceAdvisor.cs | 75 +++++++++++++++++++ .../TransactionAttributeSourceAdvisor.cs | 6 +- .../Data/NHibernate/NHDAOTests.cs | 12 ++- .../Config/Log4Net.xml | 64 ++++++++++++++++ .../Data/NHibernate/AccountController.cs | 24 ++++++ .../Data/NHibernate/Controllers.xml | 11 +++ .../Data/NHibernate/Dao.xml | 63 ++++++++++++++++ .../Data/NHibernate/IAccountController.cs | 7 ++ .../Data/NHibernate/NHDAOTests.xml | 55 ++++++++------ .../Data/NHibernate/Services.xml | 52 +++++++++++++ .../RecreateDatabases.sql | 3 +- ...NHibernate21.Integration.Tests.2008.csproj | 26 ++++++- ....NHibernate21.Integration.Tests.dll.config | 11 +++ .../Config/TxNamespaceParserTests.cs | 4 +- 17 files changed, 470 insertions(+), 44 deletions(-) create mode 100644 src/Spring/Spring.Data/Transaction/Interceptor/AbstractTransactionAttributeSourcePointcut.cs create mode 100644 src/Spring/Spring.Data/Transaction/Interceptor/ObjectFactoryTransactionAttributeSourceAdvisor.cs create mode 100644 test/Spring/Spring.Data.NHibernate21.Integration.Tests/Config/Log4Net.xml create mode 100644 test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/AccountController.cs create mode 100644 test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Controllers.xml create mode 100644 test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Dao.xml create mode 100644 test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/IAccountController.cs create mode 100644 test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Services.xml diff --git a/src/Spring/Spring.Data/Spring.Data.2008.csproj b/src/Spring/Spring.Data/Spring.Data.2008.csproj index 31ccbaf3..e6e49977 100644 --- a/src/Spring/Spring.Data/Spring.Data.2008.csproj +++ b/src/Spring/Spring.Data/Spring.Data.2008.csproj @@ -1,7 +1,7 @@  Local - 9.0.21022 + 9.0.30729 2.0 {AE00E5AB-C39A-436F-86D2-33BFE33E2E40} Debug @@ -247,6 +247,7 @@ + @@ -255,6 +256,7 @@ + diff --git a/src/Spring/Spring.Data/Transaction/Config/AttributeDrivenObjectDefinitionParser.cs b/src/Spring/Spring.Data/Transaction/Config/AttributeDrivenObjectDefinitionParser.cs index f2051028..a62009e1 100644 --- a/src/Spring/Spring.Data/Transaction/Config/AttributeDrivenObjectDefinitionParser.cs +++ b/src/Spring/Spring.Data/Transaction/Config/AttributeDrivenObjectDefinitionParser.cs @@ -65,28 +65,40 @@ namespace Spring.Transaction.Config protected override AbstractObjectDefinition ParseInternal(XmlElement element, ParserContext parserContext) { ConfigureAutoProxyCreator(parserContext, element); - - string transactionManagerName = GetAttributeValue(element, TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE); - Type sourceType = typeof(AttributesTransactionAttributeSource); + + //Create the TransactionAttributeSource + RootObjectDefinition sourceDef = new RootObjectDefinition(typeof(AttributesTransactionAttributeSource)); + sourceDef.Role = ObjectRole.ROLE_INFRASTRUCTURE; + string sourceName = parserContext.ReaderContext.RegisterWithGeneratedName(sourceDef); //Create the TransactionInterceptor definition. RootObjectDefinition interceptorDefinition = new RootObjectDefinition(typeof(TransactionInterceptor)); interceptorDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; - interceptorDefinition.PropertyValues.Add(TxNamespaceUtils.TRANSACTION_MANAGER_PROPERTY, - new RuntimeObjectReference(transactionManagerName)); - interceptorDefinition.PropertyValues.Add(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, - new RootObjectDefinition(sourceType)); + RegisterTransactionManager(element, interceptorDefinition); + interceptorDefinition.PropertyValues.Add(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, new RuntimeObjectReference(sourceName)); + String interceptorName = parserContext.ReaderContext.RegisterWithGeneratedName(interceptorDefinition); - //Create the TransactionAttributeSourceAdvisor definition. - RootObjectDefinition advisorDefinition = new RootObjectDefinition(typeof(TransactionAttributeSourceAdvisor)); - advisorDefinition.Role = ObjectRole.ROLE_INFRASTRUCTURE; - advisorDefinition.PropertyValues.Add(TRANSACTION_INTERCEPTOR, interceptorDefinition); + // Create the TransactionAttributeSourceAdvisor definition. + RootObjectDefinition advisorDef = new RootObjectDefinition(typeof(ObjectFactoryTransactionAttributeSourceAdvisor)); + advisorDef.Role = ObjectRole.ROLE_INFRASTRUCTURE; + advisorDef.PropertyValues.Add("transactionAttributeSource", new RuntimeObjectReference(sourceName)); + advisorDef.PropertyValues.Add("adviceObjectName", interceptorName); + if (element.HasAttribute(ORDER)) { - advisorDefinition.PropertyValues.Add(ORDER, GetAttributeValue(element, ORDER)); + advisorDef.PropertyValues.Add(ORDER, GetAttributeValue(element, ORDER)); } - return advisorDefinition; + return advisorDef; + } + + private void RegisterTransactionManager(XmlElement element, RootObjectDefinition interceptorDefinition) + { + string transactionManagerName = GetAttributeValue(element, TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE); + interceptorDefinition.PropertyValues.Add(TxNamespaceUtils.TRANSACTION_MANAGER_PROPERTY, + new RuntimeObjectReference(transactionManagerName)); + + } /// diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/AbstractTransactionAttributeSourcePointcut.cs b/src/Spring/Spring.Data/Transaction/Interceptor/AbstractTransactionAttributeSourcePointcut.cs new file mode 100644 index 00000000..6722a570 --- /dev/null +++ b/src/Spring/Spring.Data/Transaction/Interceptor/AbstractTransactionAttributeSourcePointcut.cs @@ -0,0 +1,59 @@ +#region License + +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System; +using System.Reflection; +using Spring.Aop.Support; + +namespace Spring.Transaction.Interceptor +{ + public abstract class AbstractTransactionAttributeSourcePointcut : StaticMethodMatcherPointcut + { + #region Overrides of StaticMethodMatcher + + /// + /// Does the supplied satisfy this matcher? + /// + /// + ///

+ /// Must be implemented by a derived class in order to specify matching + /// rules. + ///

+ ///
+ /// The candidate method. + /// + /// The target (may be , + /// in which case the candidate must be taken + /// to be the 's declaring class). + /// + /// + /// if this this method matches statically. + /// + public override bool Matches(MethodInfo method, Type targetType) + { + ITransactionAttributeSource tas = TransactionAttributeSource; + return (tas == null || TransactionAttributeSource.ReturnTransactionAttribute(method, targetType) != null); + } + + #endregion + + protected abstract ITransactionAttributeSource TransactionAttributeSource { get; } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/ObjectFactoryTransactionAttributeSourceAdvisor.cs b/src/Spring/Spring.Data/Transaction/Interceptor/ObjectFactoryTransactionAttributeSourceAdvisor.cs new file mode 100644 index 00000000..5eed2d0b --- /dev/null +++ b/src/Spring/Spring.Data/Transaction/Interceptor/ObjectFactoryTransactionAttributeSourceAdvisor.cs @@ -0,0 +1,75 @@ +#region License + +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System; +using Spring.Aop; +using Spring.Aop.Support; + +namespace Spring.Transaction.Interceptor +{ + public class ObjectFactoryTransactionAttributeSourceAdvisor : AbstractObjectFactoryPointcutAdvisor + { + + private ITransactionAttributeSource _transactionAttributeSource; + private IPointcut _pointcut; + + public ObjectFactoryTransactionAttributeSourceAdvisor() + { + _pointcut = new TransactonAttributeSourcePointcut(this); + } + + + private class TransactonAttributeSourcePointcut : AbstractTransactionAttributeSourcePointcut + { + private ObjectFactoryTransactionAttributeSourceAdvisor outer; + public TransactonAttributeSourcePointcut(ObjectFactoryTransactionAttributeSourceAdvisor outer) + { + this.outer = outer; + } + + #region Overrides of AbstractTransactionAttributeSourcePointcut + + protected override ITransactionAttributeSource TransactionAttributeSource + { + get { return outer._transactionAttributeSource; } + } + + #endregion + } + + public ITransactionAttributeSource TransactionAttributeSource + { + set { _transactionAttributeSource = value; } + } + + #region Overrides of AbstractPointcutAdvisor + + /// + /// The that drives this advisor. + /// + public override IPointcut Pointcut + { + get { return _pointcut; } + set { _pointcut = value; } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceAdvisor.cs b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceAdvisor.cs index 5845c589..f77582c7 100644 --- a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceAdvisor.cs +++ b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAttributeSourceAdvisor.cs @@ -26,9 +26,9 @@ using Spring.Aop.Support; namespace Spring.Transaction.Interceptor { /// - /// Advisor driven by a , used to exclude - /// a from methods that - /// are non-transactional. + /// Advisor driven by a , used to include + /// a for methods that + /// are transactional. /// /// ///

diff --git a/test/Spring/Spring.Data.NHibernate.Integration.Tests/Data/NHibernate/NHDAOTests.cs b/test/Spring/Spring.Data.NHibernate.Integration.Tests/Data/NHibernate/NHDAOTests.cs index f89f091f..bee0748d 100644 --- a/test/Spring/Spring.Data.NHibernate.Integration.Tests/Data/NHibernate/NHDAOTests.cs +++ b/test/Spring/Spring.Data.NHibernate.Integration.Tests/Data/NHibernate/NHDAOTests.cs @@ -63,9 +63,17 @@ namespace Spring.Data.NHibernate [SetUp] public void SetUp() { - BasicConfigurator.Configure(); + //BasicConfigurator.Configure(); string assemblyName = GetType().Assembly.GetName().Name; - ctx = new XmlApplicationContext("assembly://" + assemblyName + "/Spring.Data.NHibernate/NHDAOTests.xml"); + //ctx = new XmlApplicationContext("assembly://" + assemblyName + "/Spring.Data.NHibernate/NHDAOTests.xml"); + string[] contextFiles = new string[] + { + "assembly://" + assemblyName + "/Spring.Data.NHibernate/Controllers.xml", + "assembly://" + assemblyName + "/Spring.Data.NHibernate/Services.xml", + "assembly://" + assemblyName + "/Spring.Data.NHibernate/Dao.xml" + + }; + ctx = new XmlApplicationContext(contextFiles); ctx.Name = AbstractApplicationContext.DefaultRootContextName; if (!ContextRegistry.IsContextRegistered(AbstractApplicationContext.DefaultRootContextName)) diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Config/Log4Net.xml b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Config/Log4Net.xml new file mode 100644 index 00000000..606c455d --- /dev/null +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Config/Log4Net.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/AccountController.cs b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/AccountController.cs new file mode 100644 index 00000000..c82c91db --- /dev/null +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/AccountController.cs @@ -0,0 +1,24 @@ +using System; + +namespace Spring.Data.NHibernate +{ + public class AccountController : IAccountController + { + private IAccountManager accountManager; + + public IAccountManager AccountManager + { + get { return accountManager; } + set { accountManager = value; } + } + + #region Implementation of IAccountController + + public void DoWork() + { + accountManager.DoTransfer(30,30); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Controllers.xml b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Controllers.xml new file mode 100644 index 00000000..9286192a --- /dev/null +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Controllers.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Dao.xml b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Dao.xml new file mode 100644 index 00000000..8237a483 --- /dev/null +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Dao.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + Spring.Data.NHibernate21.Integration.Tests + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/IAccountController.cs b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/IAccountController.cs new file mode 100644 index 00000000..f7fd86f1 --- /dev/null +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/IAccountController.cs @@ -0,0 +1,7 @@ +namespace Spring.Data.NHibernate +{ + public interface IAccountController + { + void DoWork(); + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/NHDAOTests.xml b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/NHDAOTests.xml index 90202b4f..ccba5091 100644 --- a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/NHDAOTests.xml +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/NHDAOTests.xml @@ -1,7 +1,19 @@  + xmlns:db="http://www.springframework.net/database" + xmlns:tx="http://www.springframework.net/tx"> + + + + + + + + @@ -30,9 +42,11 @@ - + + + @@ -44,9 +58,10 @@ + - @@ -66,27 +81,18 @@ - - - - - + + + + + + + - - - - + + + + + + + --> + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Services.xml b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Services.xml new file mode 100644 index 00000000..1b1c958d --- /dev/null +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Data/NHibernate/Services.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/RecreateDatabases.sql b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/RecreateDatabases.sql index e6308104..b405b1d2 100644 --- a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/RecreateDatabases.sql +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/RecreateDatabases.sql @@ -27,7 +27,8 @@ GO CREATE DATABASE NHibernate GO -CREATE LOGIN [springqa2] WITH PASSWORD=N'springqa2', DEFAULT_DATABASE=[Spring], DEFAULT_LANGUAGE=[us_english] +CREATE LOGIN [springqa2] WITH PASSWORD=N'springqa2', DEFAULT_DATABASE=[Spring], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION = OFF, CHECK_POLICY = OFF + GO USE Spring diff --git a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate21.Integration.Tests.2008.csproj b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate21.Integration.Tests.2008.csproj index 20dc7aa4..d884e56b 100644 --- a/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate21.Integration.Tests.2008.csproj +++ b/test/Spring/Spring.Data.NHibernate21.Integration.Tests/Spring.Data.NHibernate21.Integration.Tests.2008.csproj @@ -40,6 +40,14 @@ False ..\..\..\lib\Net\2.0\DotNetMock.dll + + False + ..\..\..\examples\Spring\Spring.Data.NHibernate.Northwind\lib\net\2.0\Common.Logging.Log4Net.dll + + + False + ..\..\..\lib\Net\2.0\DotNetMock.dll + False ..\..\..\lib\NHibernate21\net\2.0\Iesi.Collections.dll @@ -140,6 +148,8 @@ + + @@ -201,6 +211,20 @@ Always + + + Always + + + + + + + + + Always + + + + + + + + + + + @@ -61,6 +71,7 @@ + diff --git a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs index 9a5b67cf..e26329ff 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Config/TxNamespaceParserTests.cs @@ -96,8 +96,8 @@ namespace Spring.Transaction.Config { Assert.IsNotNull(NamespaceParserRegistry.GetParser("http://www.springframework.net/tx")); Assert.IsTrue(ctx.ContainsObjectDefinition(AopNamespaceUtils.AUTO_PROXY_CREATOR_OBJECT_NAME)); - - string className = typeof(TransactionAttributeSourceAdvisor).FullName; + + string className = typeof(ObjectFactoryTransactionAttributeSourceAdvisor).FullName; string targetName = className + ObjectDefinitionReaderUtils.GENERATED_OBJECT_NAME_SEPARATOR + "0"; Assert.IsTrue(ctx.ContainsObjectDefinition(targetName));